原文博客:pjmike的博客html
跨域資源共享向來都是熱門的需求,咱們可使用 CORS 來快速實現 跨域訪問,只須要在服務端進行受權便可,無需在前端添加額外的設置前端
簡單說,CORS是一種訪問機制,英文全稱: Cross-Origin Resource Sharing,即咱們說的跨域資源共享。當一個資源從與該資源自己所在服務器不一樣的域或端口請求一個資源時,資源會發起一個跨域HTTP請求。好比,在一個域名下的網頁中,調用另外一個域名中的資源。java
CORS 實現跨域訪問並非一蹴而就的,須要藉助瀏覽器的支持,從原理題圖咱們能夠看到,簡單的請求(一般指 GET/POST/HEAD
方式,並無去增長額外的請求頭信息) 直接建立了跨域請求的 XMLHttpRequest
對象,而非簡單請求(那種對服務器有特殊要求的請求,好比請求方法是 PUT
或DELETE
,或者 Content-Type
字段的類型是 application/json
) 則要求先發送一個 "預檢" 請求,待服務器批准後才能真正發起跨域訪問請求。 git
下面分析摘自 阮一峯的 跨域資源共享 CORS 詳解github
對於簡單請求 (GET/POST/HEAD
,瀏覽器直接發出 CORS
請求,具體來講,就是在頭信息之中,增長一個 Origin
字段。以下圖所示:spring
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
複製代碼
上面的 Origin
字段用來講明,本次請求來自哪一個源(協議+域名+端口)。服務器根據這個值,決定是否贊成此次請求。json
若是 Origin
指定的源,不在許可範圍內,服務器會返回一個正常的 HTTP響應。瀏覽器發現,這個迴應的頭信息沒有包含 Access-Control-Allow-Origin
字段,就知道錯了,從而拋出一個錯誤,被 XMLHttpRequest
的 onerror
回調函數捕獲。後端
若是 Origin
指定的域名在許可範圍內,服務器返回的響應,會多出幾個頭信息字段api
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
複製代碼
下面總結下 簡單請求 與 CORS 有關的請求頭與響應頭跨域
Origin
字段的值,要麼是一個 *
,表示接受任意域名的請求getResponseHeader()
方法只能拿到6個基本字段,自定義的header字段是拿不到的,若是想拿到自定義的Header 字段,就必須在 Access-Control-Expose-Headers
裏面指定非簡單請求的 CORS 請求,會在正式通訊以前,增長一次 HTTP查詢請求,稱爲 "預檢"請求。下面是一個預檢請求的HTTP頭信息:
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
複製代碼
除了 Origin
字段外,還包括兩個特殊字段:
服務器收到預檢請求後,作出迴應:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
複製代碼
下面總結下,預檢請求下的迴應的與CORS相關的請求頭:
Access-Control-Request-Headers
字段,則 Access-Control-Allow-Headers
是必須的,它代表服務器支持的全部頭信息字段,不限於瀏覽器再預檢中請求的字段對於 CORS的跨域請求,主要有如下幾種方式可供選擇:
@CrossOrigin
注意:
@CrossOrigin
註解來進行細粒度更高的跨域資源控制。在任意配置類,返回一個 新的 CorsFIlter Bean ,並添加映射路徑和具體的CORS配置路徑。
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1. 添加 CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否發送 Cookie
config.setAllowCredentials(true);
//放行哪些請求方式
config.addAllowedMethod("*");
//放行哪些原始請求頭部信息
config.addAllowedHeader("*");
//暴露哪些頭部信息
config.addExposedHeader("*");
//2. 添加映射路徑
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",config);
//3. 返回新的CorsFilter
return new CorsFilter(corsConfigurationSource);
}
}
複製代碼
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否發送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedOrigins("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
複製代碼
在控制器上使用註解 @CrossOrigin:
@RestController
@CrossOrigin(origins = "*")
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello world";
}
}
複製代碼
在方法上使用註解 @CrossOrigin:
@RequestMapping("/hello")
@CrossOrigin(origins = "*")
public String hello() {
return "hello world";
}
複製代碼
使用 HttpServletResponse 對象添加響應頭(Access-Control-Allow-Origin)來受權原始域,這裏 Origin的值也能夠設置爲 "*",表示所有放行。
@RequestMapping("/index")
public String index(HttpServletResponse response) {
response.addHeader("Access-Allow-Control-Origin","*");
return "index";
}
複製代碼