跨域

跨域

什么是跨域

出现的原因是浏览器的同源策略,限制了js向另一个域的内容进行交互。所谓的同源就是:两个页面具有相同协议、主机(域名)、端口号。最常见就是ajax请求发送失败。

解决措施

  • 降域

    仅限于主域相同的情况。比如京东商城,主域都是jd.com,但商品服务(product.jd.com)、订单服务(order.jd.com)等可能不同。只需要设置document.domain='jd.com',浏览器就会认为是同域,可以共享cookie、互相请求资源等了。

  • postMessage

    利用h5新特性,window.postMessage(),用于多窗口、嵌套iframe等之间的通信,例如新建一个iframe标签,请求其他域的内容,对iframe调用postMessage方法发消息,然后进行事件监听,将监听到的内容发送回主页面。

  • JSONP

    简单,兼容性好,缺点是只支持get,原理是利用script标签无跨域限制的特性,服务端把数据封装在(根据callback)动态生成的js脚本中,前端页面请求这个js,整合到页面中。

    <!--
    服务端根据callback动态生成js:<script type="text/javascript"> dosomething("数据") </script>
    所以可以用sript标签直接请求,也可以用jq的方式请求这个动态生成的js文件获取数据
    -->
    <script src="http://test.com/data.php?callback=dosomething"></script>
    <script type="text/javascript">
        function dosomething(res){}
        // jq方式
        $.ajax({ type: "get", url: "", dataType: "jsonp", jsonp: "callback",
                success: dosomething  })
    </script>
    
  • CORS(Cross-Origin Resource Sharing)

    W3C标准。较常用。前端设置withCredentials设置为true即可,后端设置允许cors访问即可。withCredentials是指带上cookie访问。

    // 原生 true就代表withCredentials是true,
    xhr.open('post', 'http://www.domain2.com:8080/login', true);
    // jq
    $.ajax({xhrFields: {withCredentials: true}});
    // vue-resource
    Vue.http.options.credentials = true
    // axios
    axios.defaults.withCredentials = true
    

    后台:

    主要设置几个请求头字段:

    Access-Control-Allow-Origin: http://www.examples.com
    Access-Control-Allow-Methods: GET, POST, PUT, DELETE
    Access-Control-Allow-Headers: X-Custom-Header
    Access-Control-Allow-Credentials: true
    Access-Control-Max-Age: 1728000
    
    • tomcat配置filter

    • Servlet配置filter。实现Filter接口,对res添加请求头,res.addHeader();

    • http服务器层:

      • Nginx:location /
      • Apache
    • Spring、SpringBoot解决方案:

      • 在Controller上加@CrossOrigin注解

      • 全局配置类WebMvcConfigurer

        @Configuration
        public class CorsConfig implements WebMvcConfigurer {
            @Bean
            public WebMvcConfigurer corsConfigurer()
            {
                return new WebMvcConfigurer() {
                    @Override
                    public void addCorsMappings(CorsRegistry registry) {
                        registry.addMapping("/**").
                                allowedOrigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
                                allowedMethods("*"). //允许任何方法(post、get等)
        		                allowedHeaders("*"). //允许任何请求头
                                allowCredentials(true). //带上cookie信息
         exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
                    }
                };
            }
        }
        
      • 拦截器Filter

        @Component
        public class CorsFilter implements Filter {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                HttpServletResponse res = (HttpServletResponse) response;
                res.addHeader("Access-Control-Allow-Credentials", "true");
                res.addHeader("Access-Control-Allow-Origin", "*");
                res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
                res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
                if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
                    response.getWriter().println("ok");
                    return;
                }
                chain.doFilter(request, response);
            }
        
posted @ 2021-04-20 20:25  i%2  阅读(57)  评论(0)    收藏  举报