一、什么是跨域

跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。

例如:a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。注意:跨域限制访问,其实是浏览器的限制

同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域;

 

二、为什么会发生Ajax跨域

1.浏览器限制

2.跨域(协议、域名、端口)不一致

3.XHR(XMLHttpRequest)请求

三者全部满足,才会出现跨域问题

三、解决思路

1.浏览器:修改浏览器配置

2.XHR;使用其他方式(JSONP)

3.跨域:被调用方设置或者调用方使用代理隐藏跨域

四、解决方式

1.浏览器修改启动参数

通过修改启动参数,实现不对跨域进行校验。每种浏览器方式不一样,具体可以搜索浏览器配置。不推荐,局限大。

2.JSONP解决

(1)什么是JSONP?

答:Jsonp(JSON with Padding) 是 json 的一种”使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略,它是由 Netscape 提出的一个著名的安全策略,现在所有支持 JavaScript 的浏览器都会使用这个策略。

(2)使用JSONP后台需要改动吗?

答:需要。JSONP需要解析的是JS代码,如果后台返回的是JSON对象,就会报语法错误。 可以通过添加@ControllerAdvice,继承AbstractJsonpResponseBodyAdvice。构造函数中super(“callback”)。这个callback(默认)就是约定,说明如果参数中带了callback,后台就会当做JSONP请求处理。如果修改这个callback名字,Ajax中要写jsonp: “新名字”,并且后台改为super(“新名字”);

(3)JSONP的实现原理

答:JSONP请求会发送类型为script的请求,浏览器不会做校验;JSONP返回的是JS脚本;JSONP的请求会加callback参数,后台接收到参数会知道收到的是JSONP请求,进而将返回数据处理为JS。通俗点讲,就是把JSON写入了JS中,因为JS不存在跨域问题。

(4)JSONP的弊端

答:服务器需要改动代码支持,而且只支持GET方法,发送的不是XHR请求,不支持很多特性(异步、事件等)。

3.被调用解决

(1)服务器实现

使用Filter实现
@Bean
public FilterRegistrationBean registerFilter() {
    FilterRegistrationBean bean = new FilterRegistrationBean();
    bean.addUrlPatterns(“/*”);
    bean.setFilter(new CrosFilter());
    return bean;
}

CrosFilter implements Filter:
doFilter里:
HttpServletResponse res = (HttpServletResponse)response;
res.addHeader(“Access-Control-Allow-Origin”, “http://localhost:8081”);// 可以写*表示所有
res.addHeader(“Access-Control-Allow-Methods”, “GET”);// 可以写*表示所有
res.addHeader(“Access-Control-Allow-Headers”, “Content-Type”);// 请求头
res.addHeader(“Access-Control-Max-Age”, “3600”);// 缓存预警命令时间
res.addHeader(“Access-Control-Allow-Credentials”, “true”);// 允许Cookie跨域,此时Origin必须是全匹配,不能是*
res.addHeader(“Access-Control-Allow-Headers”, headers);// 允许自定义头跨域
chain.doFilter(request, response);

跨域请求分为:
简单请求:先执行,后判断
非简单请求:先发预警命令判断,后执行

(2)Nginx配置
虚拟主机:多个域名指向一个主机
nginx.conf添加:include vhost/*.conf;
新建vhost目录并添加x.conf文件:
server{
    listen 80;
    server_name x.com;

    location /{
        proxy_pass http://localhost:8080/;
       
        add_header Access-Control-Allow-Methods *;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Allow-Credentials true;

        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Headers $http_access_control_request_headers;

        if ($request_method = OPTIONS){
            return 200;
        }
    }
}

(3)Apache配置
配置(httpd.conf):
打开LoadModule vhost… 模块
打开LoadModule proxy_module… 模块
打开LoadModule proxy_http_module… 模块
打开Include conf/extra/httpd-vhosts.conf

找到httpd-vhosts.conf文件
新增
<VirtualHost *:80>
    ServerName x.com
    ErrorLog “logs/x.com-error.log”
    CustomLog “logs/x.com-access.log” common
    ProxyPass / http://localhost:8080/

  #响应头相关配置,百度谷歌自查
</VirtualHost>

(4)Spring框架

配置:Controller类或方法上添加@CrossOrigin注解

4.调用方解决

(1)隐藏跨域-Nginx

host中添加:127.0.0.1 x.com y.com
server{
    listen 80;
    server_name y.com;

    location /{
            proxy_pass http://localhost:8081/;
        }

    location /ajaxserver{
            proxy_pass http://localhost:8080/test/;
        }
    }
}

(2)隐藏跨域-Apache

<VirtualHost *:80>
    ServerName y.com
    ErrorLog “logs/y.com-error.log”
    CustomLog “logs/y.com-access.log” common
    ProxyPass /ajaxserverapache http://localhost:8080/test
    ProxyPass / http://localhost:8080/
</VirtualHost>