cors?
CORS(跨域资源共享)的核心机制是 由后端服务器(bbb.com)决定是否允许前端(aaa.com)的跨域请求
当浏览器访问 aaa.com 的页面,并向 bbb.com/list 发起请求时,浏览器会先检查是否跨域:由于 aaa.com 和 bbb.com 的域名不同,属于跨域请求;触发 CORS,浏览器会发送 OPTIONS 预检请求到后端,请求头包含 Origin: aaa.com,服务器(bbb.com)返回响应头
- Access-Control-Allow-Origin: aaa.com
- Access-Control-Allow-Credentials: true
- Access-Control-Allow-Methods: GET, POST // 该字段的目的是明确允许哪些业务 HTTP 方法
这个接口 options 响应头告知前端 aaa.com 做跨域请求过来是可以的
如果 cors 验证失败,浏览器会拦截请求并抛出 CORS 错误
其实本质是可以这么理解:具体哪个域名可以请求我的后端服务接口,是由我后端自己控制的,我后端可以控制成让 aaa.com 的域名可以访问,也可以控制成让 bbb.com 的域名可以访问,本质是浏览器先发一个 options 预检请求,通过响应头让浏览器知道能否跨域访问,可以的话就访问了,不可以的话浏览器就报 cors 错误
浏览器发送 OPTIONS 预检请求的唯一前提是 跨域且非简单请求,如果请求是同源的,无论是否为非简单请求,浏览器都不会发送 OPTIONS 预检请求
特殊的:
简单请求:请求 method 是 get/post/head 其一,且 req header 只能包含
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type(值只能是 application/x-www-form-urlencoded 或者 multipart/form-data 或者 text/plain)
如果是简单请求,即使浏览器域名和页面接口请求域名不一致,也不会触发浏览器 cors,自然也不需要预检请求 options
简单请求之所以不会触发 cors,是因为浏览器这些请求风险较低,
代码
拦截器:
@Component
public class CorsInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 先判断 reqHeader 中 Origin 对应的浏览器访问的域名如果是后端允许跨域的域名 aaa.com,是的话,后续就塞入到 Access-Control-Allow-Origin 中,表示告诉前端,这个域名的跨域请求是被允许的
response.setHeader("Access-Control-Allow-Origin", "aaa.com");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
return true;
}
}
注册拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CorsInterceptor corsInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(corsInterceptor)
.addPathPatterns("/**") // 所有路径生效
.excludePathPatterns("/public/**"); // 排除无需跨域的路径
}
}
也有其他方式配置 cors:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("aaa.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Content-Type", "Authorization")
.allowCredentials(true)
.maxAge(3600);
}
}