
👆關注微信公眾號,獲取更多編程內容
跨域資源共享(CORS,請求協議,請求地址,請求端口三者必須相同才是同一服務器,否則都要進行跨域操作)標准新增了一組 HTTP 首部字段,允許服務器聲明哪些源站有權限訪問哪些資源。另外,規范要求,對那些可能對服務器數據產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。服務器確認允許之后,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。
常見的CORS的HTTP頭
其根本是在請求響應結果中添加響應頭,來表名服務支持CORS,因此常見的CORS頭如下:
名稱 | 示例 | 作用 |
---|---|---|
Access-Control-Allow-Origin | https://www.zhoutao123.com | 表明它允許"www.zhoutao123.com"發起跨域請求 |
Access-Control-Max-Age | 3628800 | 表明在3628800秒內,不需要再發送預檢驗請求 |
Access-Control-Allow-Methods | GET,PUT, DELETE | 允許GET、PUT、DELETE的外域請求 |
Access-Control-Allow-Headers | content-type | 允許跨域請求包含content-type頭 |
CORS執行流程
CORS在首次請求跨域服務器之前,都要進行預檢請求 ,會首先發送一個OPTIONS請求檢查是否支持CORS,待服務器響應之后,在進行后續的操作,具體流程圖下,當然並不是每個請求都會發送OPTIONS請求,在確認支持CORS之后,瀏覽器會把驗證結果緩存下來,緩存的有效時間可以通過 Access-Control-Max-Age
來控制:
預檢請求重定向
大多數瀏覽器不支持針對於預檢請求的重定向。如果一個預檢請求發生了重定向,瀏覽器將報告錯誤:
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
CORS 最初要求該行為,不過在后續的修訂中廢棄了這一要求。不過我們還是盡量不要對OPTIONS預檢請求做重定向處理.
- 注意:因為CORS在發送真正的請求之前會發送OPTIONS請求,以此來驗證服務器是否支持跨域,此次預檢請求不攜帶任何真正請求的參數,當前也不包括我們設定的token參數,因此如果你的Spring應用或者其他應用在攔截器上做了驗證,請注意不要攔截OPTIONS請求,否則CORS支持會開啟失敗.
SpringBoot開啟CORS
非全局配置
So that the RESTful web service will include CORS access control headers in its response, you just have to add a @CrossOrigin annotation to the handler method
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
//允許跨域的服務器
@AliasFor("origins")
String[] value() default {};
//和上面是一樣的 AliasFor
@AliasFor("value")
String[] origins() default {};
//允許頭部
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
/**
* The list of supported HTTP request methods.
* <p>By default the supported methods are the same as the ones to which a
* controller method is mapped.
*/
RequestMethod[] methods() default {};
String allowCredentials() default "";
/**
* The maximum age (in seconds) of the cache duration for preflight responses.
* <p>This property controls the value of the {@code Access-Control-Max-Age}
* response header of preflight requests.
* <p>Setting this to a reasonable value can reduce the number of preflight
* request/response interactions required by the browser.
* A negative value means <em>undefined</em>.
* <p>By default this is set to {@code 1800} seconds (30 minutes).
*/
long maxAge() default -1;
}
只要在SpringBoot的Mapper()接口中添加並配置此注解即可
//根據CrossOrigin的注釋可以再請求參數的不存在的時候,CORS支持的方法和Mapper支持的方法一致
@CrossOrigin(origins = "http://localhost:9000")
@GetMapping("/test")
public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in tesing ====");
return "SUCCESS";
}
全局配置
在大量接口需要開啟CORS支持的時候,上面的方式顯然不適合操作,因此Spring提供了全局配置CORS支持的方式。
@Bean
@SuppressWarnings("deprecation")
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
log.info("CORS 配置參數 origins = {} url = {}", allowedOrigins, allowedUrl);
registry
.addMapping("/**")
.allowedMethods("GET", "POST", "PATCH", "DELETE", "PUT", "OPTIONS")
.allowedOrigins("http://localhost:9090");
}
};
}