关于「跨域」的一些基础知识这里就不讨论了,如果需要先充电的同学请移步这里看看:跨域资源共享 CORS 详解。在这里,我就直接抛出问题:由于浏览器出于安全目的而制定的 同源策略,导致 Web 页面通过 XMLHttpRequest 发起 ajax 请求的时候,如果访问非同源服务接口,则报错:has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource。
言外之意:“跨域”是针对网页中通过 XMLHttpRequest 对象发起的 ajax 请求才会出现的问题。在 Android 和 IOS 原生开发、基于 http 的微服务与微服务之间的调用都是不存在跨域问题的。这点需要先厘清楚。
跨域问题常用解决办法
归纳起来,解决跨域问题有两种基本的思路。
- 一种就是在跨域的基础上本质都是要往 response 的头信息中追加
Access-Control-*
相关的属性。这种思路根据不同的上下文环境,也只是实现方式不同而已。 - 一种就是规避出现跨域环境,也就是在部署阶段将前后端部署在同一个域下。
方法一:强撸追加 Access-Control-*
这是一种最简单粗暴也很有效的方法。即在能获取 HttpServletResponse 对象的上下文环境中,使用 response.addHeader(); 方法来增加 Access-Control-*
相关属性。这种上下文有可能是具体的某个 Controller 方法,也可以是原生 Servlet 环境亦或是 Struts、SpringMVC 的过滤器、拦截器等。下面以 SpringMVC 的拦截器举例说明。
public class CrossOriginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getHeader(HttpHeaders.ORIGIN) != null) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.addHeader("Access-Control-Max-Age", "86400");
}
return true;
}
}
方法二:注解追加 Access-Control-*
在 SpringMVC 的环境下,我们也可以在 Controller 的类上或方法使用 @CrossOrigin 注解来实现跨域,Access-Control-*
相关属性也会自动的追加到 response 头信息里去。
这种方式的优劣是很明显的,大家根据实际情况酌情使用。@CrossOrigin (
如果需要,这里可以设置具体属性值):@CrossOrigin(value="*", allowCredentials="true")
方法三:网关追加 Access-Control-*
这是在微服务开发中特有的一种方式,具体配置方式根据不同的网关框架而定。
方法四:通过部署来规避跨域
同步部署规划,可以有效规避跨域问题的出现。比如,如下盘古通用权限参考实现系统的部署方法。
如上,则可将前后端部署在同一个域下从而有效避免了跨域问题。