CORS

原理:Cross-Origin Resource Sharing ,即跨源资源共享,在现代版浏览器上,增加一些新的请求头和响应头,浏览器通过这些请求头和响应头,判断是否允许我们跨域访问,以及允许的访问的时间,允许访问的网站等等。

案例:

a域:html

 <input type="button" onclick="btnClick" value="请求资源"/>

a域:前端js

   <script src="/javascripts/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">
 
        //按钮点击事件
        function btnClick(){
            //发送ajax请求到b域获取资源
            $.get("http://www.b.com/getData",function(data){
                alert(data);
            });
        }
    </script>

 b域:后端代码(java)

@RequestMapping(value = "/getData",  method=RequestMethod.GET)  
@ResponseBody   
public String getData(HttpServletResponse response ) throws IOException{  
    //设置响应头,允许所有网站跨域访问本资源
    response.setHeader("Access-Control-Allow-Origin", "*");  
    //只允许www.a.com访问本资源
    // response.setHeader("Access-Control-Allow-Origin", "http://www.a.com");  
    return "success";
}

  • 流程:

    1.a域的用户点击按钮后,发送ajax请求到b域获取资源

    2.b域设置响应头"Access-Control-Allow-Origin",值为"*",表示允许所有网站跨域访问资源,然后返回资源

3.a域的用户的浏览器接收b域返回的资源后,判断响应头"Access-Control-Allow-Origin"中设置的值是否允许a域访问,因为此时为"*",表示允许访问,浏览器将b域的资源放行,a域获取到资源

优点:1.充分利用现代浏览器的特性,配置最少,方便维护2支持所有类型的http请求缺点:1.有些低版本的浏览器不兼容该特性,如IE6,IE7其他:cors是最推荐的使用跨域的解决方案,其充分利用现代浏览器的新特性,使用相对来说比较少的配置,就可以在支持所有类型的http请求下达到跨域的效果,但如果目标用户的浏览器比较原始,就需要权衡一下该方案,以下图片为支持cors的浏览器,绿色表示支持cors,该信息统计为2014年,最新统计请参考戳我,关于cors的其他请求头和响应头请参考戳我其他解决方案:现在主流推荐的是使用cors解决跨域问题,之所有会出现跨域,是因为现代的浏览器在通过ajax访问非本域的资源成功后,不会直接将资源返还给本域,在这之前,会判断一下ajax发送方的域名与请求的资源所在的域是否匹配,匹配则放行,如果不匹配,会去判断响应头中,是否包含"Access-Control-Allow-Origin",且进一步去判断该响应头对应的值是否与ajax发送方的域名匹配,只有在匹配的情况下,才会将资源放行,具体流程如下

wKiom1hjNSCj5L-zAADzNqiJTis945.png

所以我们的解决思路是

   1取消浏览器的安全检查:

  • chrome通过命令屏蔽跨域安全检查

  2在响应头中加上Access-Control-Allow-Origin允许跨域访问:
 

  •  tomcat设置过滤器

  • nginx设置响应头

  • chrome通过插件实现跨域



chrome通过命令屏蔽跨域安全检查

可参考戳我, 如果添加–disable-web-security无效的话,重启下浏览器并确保所有chrome后台进程已被关闭,重启后再次访问就可以了


tomcat设置过滤器

 创建过滤器

package com.filter;
 
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
/**
 * Created by zhangyajun
 */
public class CORSFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, 
    ServletResponse servletResponse, 
    FilterChain filterChain) throws IOException,
     ServletException {
        HttpServletResponse httpResponse = 
        (HttpServletResponse) servletResponse;
        //此处*代表允许所有域名跨域,也可以指定具体的域名,多个域名用","隔开
        httpResponse.addHeader("Access-Control-Allow-Origin", "*");
        //设置允许www.b.com和www.c.com跨域
        //httpResponse.addHeader("Access-Control-Allow-Origin", 
                                "http://www.b.com,http://www.c.com");
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
    @Override
    public void destroy() {
 
    }
}

web.xml配置:注意配置顺序,CorsFilter过滤器放在最前面

    <!--允许跨域过滤器-->
    <filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>com.filter.CORSFilter</filter-class>
    </filter>
     
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

nginx设置响应头

location / {  

    add_header Access-Control-Allow-Origin *;  

}  

这样在所有的响应头上会默认加上Access-Control-Allow-Origin *,允许所有域名跨域访问


chorme通过插件实现跨域

下载戳我插件,安装到chrome的拓展程序中,该插件会自动添加响应头Access-Control-Allow-Origin *,从而达到跨域效果,在测试时方便使用。