OSS部署静态网站碰到的跨域问题

oss如何部署静态网站?

阿里云教程。教程示例:使用自定义域名设置静态网站托管

部署之后发现静态页面请求后端出现跨域异常。

提示:

后端服务为spring-boot项目,在Controller层有加@CrossOrigin注解进行允许跨域请求。依旧不行。

查看nginx access日志。发现跨域请求为OPTIONS请求。

什么是OPTIONS 请求?

原来浏览器会在发送真正请求之前,先发送一个方法为OPTIONS的预检请求 Preflighted requests 这个请求是用来验证本次请求是否安全的,而且并不是所有请求都会发送,需要符合以下条件:

  • 请求方法不是GET/HEAD/POST

  • POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
    请求设置了自定义的header字段

  • 对于管理端的接口,我有对接口进行权限校验,每次请求需要在header中携带自定义的字段(token),所以浏览器会多发送一个OPTIONS请求。

那为什么OPTIONS请求报错了。。。

经过debug发现,OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,如token,但是我在过滤器是有校验token字段,此时 token为NULL,所以验证不通过,抛出了一个异常。

如何解决OPTIONS请求?

新增一个拦截器类 CorsInterceptor 实现 HandlerInterceptor 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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;
}

}

需将跨域拦截器放在校验拦截器之上

我把原来的跨域配置 addCorsMappings 删除了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Resource
private LoginInterceptor loginInterceptor;
@Resource
private CorsInterceptor corsInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
// 跨域拦截器需放在最上面
registry.addInterceptor(corsInterceptor).addPathPatterns("/**");
}

}

为什么还是报错?

因为我的TOKEN验证是写到过滤器里面,spring 过滤器的执行是优先于拦截器的。所以我们在过滤器的请求中加上放行OPTIONS请求。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
throws IOException, ServletException {
// Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) srequest;
// 如果是OPTIONS则直接放行
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
filterChain.doFilter(srequest, sresponse);
return;
}
.............
}

问题解决