springboot

SpringBoot--实战开发--处理OPTIONS请求(三十

2019-06-26  本文已影响11人  无剑_君

一、为什么出现OPTIONS?

同源策略
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
前端地址:

http://127.0.0.1:8082

后端地址:

http://127.0.0.1:8002

这两个地址虽然ip地址和协议都一样,但是端口不一样,所以并不满足同源,这样就造成了跨域的问题。
解决方案
配置addCorsMappings
新增一个类实现 WebMvcConfigurer 接口,然后给这个类加上 @Configuration 注解,最后实现 addCorsMappings 方法就ok了。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .maxAge(3600)
                .allowCredentials(true);
    }
}
OPTIONS请求

原因
原来浏览器会在发送真正请求之前,先发送一个方法为OPTIONS的预检请求 Preflighted requests 这个请求是用来验证本次请求是否安全的,而且并不是所有请求都会发送,需要符合以下条件:
请求方法不是GET/HEAD/POST
POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
请求设置了自定义的header字段
对于管理端的接口,我有对接口进行权限校验,每次请求需要在header中携带自定义的字段(token),所以浏览器会多发送一个OPTIONS请求。

经过debug发现,OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,而后台校验token字段时 token为NULL,所以验证不通过,抛出了一个异常。

二、解决方法

1、定义拦截器

@Component
public class CorsInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "86400");
        response.setHeader("Access-Control-Allow-Headers", "*");

        // 如果是OPTIONS则结束请求
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            response.setStatus(HttpStatus.NO_CONTENT.value());
            return false;
        }
        return true;
    }
}
  1. 使用拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 跨域拦截器需放在最上面
        registry.addInterceptor(new CorsInterceptor()).addPathPatterns("/**");
    }
上一篇 下一篇

猜你喜欢

热点阅读