Spring對跨域CORS的支持

一、概述

跨域,即CORS,全稱Cross-origin resource sharing, 跨域資源共享。是一個W3C的標準。

二、跨域所解決的問題

一般來說,瀏覽器具有同源策略,它限制了瀏覽器從一個源加載的文檔或腳本,不能與來自另一個源的資源進行交互,這是一種保護策略。

同源的定義:兩個源的 協議、域名、端口都相同,則他們是同源的。

同源策略控制了不同源之間的交互,這些交互通常分爲如下三類:

  • 允許跨域寫操作:如重定向和表單提交等
  • 允許跨域資源嵌入:如使用<img>嵌入圖片,使用<script>嵌入腳本源文件等
  • 不允許跨域讀操作:如使用js讀取另一個源的信息

解決跨域問題的方式,官方提供了標準,就是CORS。

三、具體方案

CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能。

整個CORS通信過程,都是由瀏覽器自動完成,不需要我們去參與。當瀏覽器檢測到跨域時,會自動添加一些消息用戶不會有感覺。因此,CORS的關鍵是服務器

四、 兩種請求

瀏覽器將CORS分爲兩類:簡單請求和非簡單請求

簡單請求

(1) 請求方法是以下三種方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的頭信息不超出以下幾種字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

滿足以上條件的是簡單請求,不滿足的就是非簡單請求

簡單請求會自動在請求頭上加一個Origin字段,說明了協議、域名、端口

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...

服務器根據該字段信息,決定是否同意該請求。如同意則返回消息頭會包含如下信息

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

第一個是必須的:表示能夠接受的域名請求

第二個是可選的:表示是否允許cookie發送

第三個是可選的:表示瀏覽器可以拿到的額外字段值。默認情況下CORS請求時只能拿到6個基本字段,這裏指定了額外的字段。

非簡單請求

非簡單請求是對服務器有特殊要求的請求,如傳輸JSON等。

在進行傳輸前,會先進行一次查詢請求,詢問服務器是否支持跨域,以及支持哪些HTTP方法和字段。稱爲preflight。只有當查詢通過後纔會發送正式的消息。

一個preflight請求頭如下,表示要發送PUT請求,並且額外發送的請求頭字段爲X-Custom-Header

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...

響應如下,說明了允許的源,允許的方法,還有允許的請求頭字段。

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

上面通過後,瀏覽器將會正式發送跨域請求,就像簡單請求的方式一樣。

除了上面提到的幾種返回字段外,還有一個字段

Access-Control-Max-Age: 1728000

它表示preflight的有效期,即本次preflight通過後,接下來的1728000秒內,該源不用再進行preflight操作即可直接發送請求了。

五、Spring對跨域的支持

局部跨域的支持

可以使用@CrossOrigin註解配合RequestMapping,針對某個特定的方法應用跨域設置,如下

	@CrossOrigin(maxAge = 1800)
    @RequestMapping(value = "/check")
    @ResponseBody
    public APIResult<User> findBoxList(HttpServletRequest request) {

全局跨域支持

可以在配置文件中,使用mvc:cors配置全局的跨域支持

<mvc:cors>
    <mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST,DELETE,PUT,PATCH,OPTIONS"/>
</mvc:cors>
  • path: 指定適用的url

  • Allowed-origin: 允許的源

  • Allow-credentials: 允許發送cookie

  • Max-age: preflight的有效期

  • Allowed-methods: 允許的method

  • Allowed-headers: 允許的消息頭字段

  • Exposed-headers: 額外允許的消息頭字段

或者在實現了WebMvcConfigurer接口的配置類中重寫方法

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
    /**
     * 跨域配置
     */
    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**")
            .allowedOrigins("*").allowCredentials(true).maxAge(180)
            .allowedMethods("GET","POST","DELETE","PUT","PATCH","OPTIONS");
    }
	... ...
}

CORS過濾器

爲了實現與其它不支持本地CORS的庫一起使用,Spring還提供了一個更加通用的跨域過濾器,CorsFilter,繼承該類,配置成過濾器即可工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章