跨域
跨域
什么是跨域
出现的原因是浏览器的同源策略,限制了js向另一个域的内容进行交互。所谓的同源就是:两个页面具有相同协议、主机(域名)、端口号。最常见就是ajax请求发送失败。
解决措施
-
降域
仅限于主域相同的情况。比如京东商城,主域都是jd.com,但商品服务(product.jd.com)、订单服务(order.jd.com)等可能不同。只需要设置
document.domain='jd.com'
,浏览器就会认为是同域,可以共享cookie、互相请求资源等了。 -
postMessage
利用h5新特性,window.postMessage(),用于多窗口、嵌套iframe等之间的通信,例如新建一个iframe标签,请求其他域的内容,对iframe调用postMessage方法发消息,然后进行事件监听,将监听到的内容发送回主页面。
-
简单,兼容性好,缺点是只支持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); }
-
-