文章目錄
- cors?
- 代碼
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 {@Overridepublic 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 {@Autowiredprivate CorsInterceptor corsInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(corsInterceptor).addPathPatterns("/**") // 所有路徑生效.excludePathPatterns("/public/**"); // 排除無需跨域的路徑}
}
也有其他方式配置 cors:
@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("aaa.com").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("Content-Type", "Authorization").allowCredentials(true).maxAge(3600);}
}