Java Web前后端分离中CORS配置及OPTIONS请求优化
Java Web前后端分离中CORS配置及OPTIONS请求优化
0x00 CORS 概述
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。现代浏览器支持在 API 容器中(例如
XMLHttpRequest
或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。
CORS存在的主要原因就是浏览器的同源策略。
预检请求(preflight request)
对于跨域请求,浏览器首先通过OPTIONS方法发送一个预检请求,用于判断服务端是否可以接收当前请求,然后才会发送真正的HTTP请求。
请求头部
在HTTP请求的头部,主要有如下几个字段和CORS相关:
Access-Control-Allow-Origin
该字段用于标识服务端可以接收来自什么地方的请求,为"*"
时表示可以接收;
Access-Control-Allow-Methods
该字段用于标识服务端可以接收什么样的请求,主要包括GET
、POST
、OPTIONS
、PUT
、DELETE
等;
Access-Control-Allow-Headers
该字段存在预检请求中,用于标识服务端允许的头部内容,主要包括Accept
、Accept-Language
、Content-Language
、Content-Type
等,服务端返回内容到Access-Control-Expose-Headers
字段;
Access-Control-Max-Age
该字段存在预检请求中,用于标识服务端设置的预检请求信息缓存时间。即在服务端设置的时间范围内,只需发送一次OPTIONS请求;
Access-Control-Allow-Credentials
该字段存在预检请求中,用于标识是否接收浏览器端的认证信息。认证信息主要包括Cookie
、authorization headers
等内容。该字段和浏览器中的withCredentials
相对应,浏览器端用于标识是否发送认证信息,服务端用于标识是否接收认证信息。
0x01 Filter中配置CORS
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.addHeader("Access-Control-Allow-Origin", "path/to/origin");
httpServletResponse
.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
httpServletResponse.setHeader("Access-Control-Allow-Headers",
httpServletRequest.getHeader("Access-Control-Request-Headers"));
httpServletResponse.addHeader("Access-Control-Max-Age", "86400");
httpServletResponse.addHeader("Access-Control-Allow-Credentials","false");
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
return super.preHandle(request, response);
}
0x02 SpringBoot中配置CORS
全局配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("path/to/origin")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("POST", "GET", "OPTIONS")
.maxAge(86400)
.allowCredentials(false);
}
}
单独配置
@CrossOrigin(
origins = "path/to/origin",
methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS},
allowedHeaders = "*",
allowCredentials = "false",
maxAge = 86400)
0x03 OPTIONS请求优化
右上可知,Access-Control-Max-Age字段用于标识预检请求的缓存时间,因此可以设置Access-Control-Max-Age为较大值来优化OPTIONS请求,在设置的时间段内,只有第一次请求是需要发送OPTIONS的,后面的请求均不需要。
但是,预检请求只针对于单个URL,而不是整个域名,即对http://domain/a
和http://domain/b
这2个请求,均需要发送OPTIONS。