·
什么是跨域
在目前的前后端分离开发模式下,前端使用 Ajax 访问后端提供的接口获取数据,产生报错。
跨域发生的原因
1. 浏览器的限制
2. 发生跨域访问
3. 发送的是 XHR(XMLHttpRequst) 请求
三者同时发生,就会发生跨域问题
解决方式
因为是三者同时发生,才能发生跨域问题,因此针对三者,处理其中的一个即可。
首先是浏览器的限制,需要指定参数让浏览器不做校验,但方法不太合理,需要每个人都去做修改。其次是发送的请求不要是 XHR 类型的,解决方式是 JSONP 。最后是针对跨域,分为两点,一是让被调用方支持跨域,在响应头中添加参数,表示支持跨域访问,核心是支持跨域,二是让调用方在请求中使用代理,将从 A 域名发送到 B 的请求通过代理,让 B 认为是从本域名来的,核心是隐藏跨域。
具体解决方式
针对浏览器,通过命令行的方式启动,让其不要做跨域校验即可。
1 eg:chrome --disable-web-security
针对 XHR 方式,本身浏览器发送的是 json 请求,通过 jsonp 的方式,将其变为 js 的方式,核心是通过动态添加 script 的方式来封装了请求,从而解决跨域问题。
使用这种方式需要修改服务端的代码,修改方式如下:
@ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice ( public JsonpAdvice() { super("callback"); } }
前端通过制定 dataType 的方式来发送请求,如下所示
$.ajax({ url:base+"/get1", dataType: "jsonp", jsonp: "callback", cache: true, type:"post", success:function(json){ result = json; } })
但使用这种方式仍然是不好的方式,其有如下弊端
1. 需要服务器端改变代码,如果涉及调用第三方接口,根本无法完成;
2. 只支持 GET 请求,在真是的业务场景中十分受限;
3. 因为改变了请求的类型,从 XHR 变为了 js 方式,因此 XHR 的很多优良特性无法使用。
因此,解决跨域问题最好的方式还是通过解决跨域访问来解决,使用服务器端支持跨域或调用端隐藏跨域来解决。
?
调用方解决跨域(支持跨域)的3种解决方式
1. 服务器端实现
2. Nginx 配置
3. Apache 配置
使用 Filter 来实现
通过过滤器在所有请求的 Response 中添加字段来支持跨域访问。
1 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 2 3 HttpServletRequest req = (HttpServletRequest) request; 4 5 HttpServletResponse res = (HttpServletResponse) response; 6 7 String origin =req.getHeader("Origin"); 8 9 if (!StringUtils.isEmpty(origin)){ // 动态添加访问地址,使得所有的域名都可以跨域访问 10 11 res.addHeader("Access-Control-Allow-Origin",origin); 12 13 } 14 15 String headers = req.getHeader("Access-Control-Request-Headers"); 16 17 if (!StringUtils.isEmpty(headers)){ // 动态添加自定义访问头 18 19 res.addHeader("Access-Control-Allow-Headers",headers); 20 21 } 22 23 res.addHeader("Access-Control-Allow-Methods","*"); 24 25 res.addHeader("Access-Control-Max-Age","3600"); 26 27 res.addHeader("Access-Control-Allow-Credentials","true"); 28 29 chain.doFilter(request,response); 30 31 } 32 33 34 35 @Bean 36 37 FilterRegistrationBean registrationBean(){ 38 39 FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean(); 40 41 filterRegistrationBean.addUrlPatterns("/*"); 42 43 filterRegistrationBean.setFilter(new CrosFilter()); 44 45 filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); 46 47 filterRegistrationBean.setName("Ajax"); 48 49 return filterRegistrationBean; 50 51 }
被调用方解决跨域(隐藏跨域)的解决方式
在 Spring 框架中的解决方式:在需要的类或方法上加上注解, @CrossOrigin
Nginx 配置
Apache 配置
Nginx 和 Apache 的解决方式因为涉及到其两个框架的方式,因为还没有深入了解过,所以在这没有叙述,以后深入学习过后,再详细编写。
原文地址:https://www.cnblogs.com/JRookie/p/Ajax-SpringBoot.html