后台服务端增加拦截器用于处理所有请求并加上允许跨域的头来解决http请求跨域问题
1.简介
出于安全考虑,并不是所有域名都可以访问后端服务。在正式发送请求之前,浏览器会根据需要发起一次预检(也就是option请求),用来让服务端返回允许的方法(如get、post),被跨域访问的Origin(来源或者域),还有是否需要Credentials(认证信息)等。
2.两种请求方式
浏览器将CORS请求分为两类:简单请求(simple request)和非简单请求(not-simple-request),简单请求浏览器不会预检,而非简单请求会预检。这两种方式怎么区分?
同时满足下列三大条件,就属于简单请求,否则属于非简单请求(例如请求头设置了自定义的header字段)
(1).请求方式只能是:GET、POST、HEAD
(2).HTTP请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID
(3).Content-type只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,客户端会直接发送请求并在请求头增加一个origin字段,来说明本次请求来自哪个源(协议+域名+端口)。服务器根据这个值,来决定是否同意该请求,服务器返回的响应会多几个头信息字段,如下:
(1).Access-Control-Allow-Origin:该字段是必须的,* 表示接受任意域名的请求,还可以指定域名
(2).Access-Control-Allow-Credentials:该字段可选,是个布尔值,表示是否可以携带cookie,(注意:如果Access-Control-Allow-Origin字段设置*,此字段设为true无效)
(3).Access-Control-Allow-Headers:该字段可选,里面可以获取Cache-Control、Content-Type、Expires等,如果客户端的请求头添加了自定义header字段,就需要在这里把自定义字段配置进去,否则会报跨域的错Request header field xxx is not allowed by Access-Control-Allow-Headers in preflight response.
非简单请求是对那种对服务器有特殊要求的请求,比如请求方式是PUT或者DELETE,或者Content-Type字段类型是application/json。都会在正式通信之前,增加一次HTTP请求,称之为预检。浏览器会先询问服务器,当前网页所在域名是否在服务器的许可名单之中,服务器允许之后,浏览器会发出正式的XMLHttpRequest请求,否则会报错。
解决方案:
在服务端增加一个拦截器,用于处理所有请求并加上允许跨域的头,如下代码preHandle
配置后,客户端才能继续发正式的请求。
public class CommonInterceptor implements HandlerInterceptor {
private List<String> excludedUrls;
public List<String> getExcludedUrls() {
return excludedUrls;
}
public void setExcludedUrls(List<String> excludedUrls) {
this.excludedUrls = excludedUrls;
}
/**
* 在业务处理器处理请求之前被调用 如果返回false
* 从当前的拦截器往回执行所有拦截器的afterCompletion(),
* 再退出拦截器链, 如果返回true 执行下一个拦截器,
* 直到所有的拦截器都执行完毕 再执行被拦截的Controller
* 然后进入拦截器链,
* 从最后一个拦截器往回执行所有的postHandle()
* 接着再从最后一个拦截器往回执行所有的afterCompletion()
* @param request
* @param response
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept");
return true;
}
// 在业务处理器处理请求执行完成后,生成视图之前执行的动作
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { }
/**
*
* 在DispatcherServlet完全处理完请求后被调用
* 当有拦截器抛出异常时,
* 会从当前拦截器往回执行所有的拦截器的afterCompletion()
* @param request
* @param response
* @param handler
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception { }
}
相关资源https://blog.csdn.net/kahhy/article/details/81563063?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.baidujs&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.baidujs