1. 程式人生 > >nginx配置CORS實現跨域

nginx配置CORS實現跨域

簡介

之前專案中遇到過幾次跨域訪問,通過百度或谷歌查詢在nginx配置相關header予以解決,若不管用就沒其他辦法了;從來沒有真正深入瞭解過,下面我們就來認識下CORS及在nginx中如何配置。

CORS

CORS是一個W3C標準,全稱是跨域資源共享(Cross-origin resource sharing)。它允許瀏覽器向跨源伺服器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

簡單來說就是跨域的目標伺服器要返回一系列的Headers,通過這些Headers來控制是否同意跨域。
CORS提供的Headers,在Request包和Response包中都有一部分:

#HTTP Response Header
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Expose-Headers
Access-Control-Max-Age
#HTTP Request Header
Access-Control-Request-Method
Access-Control-Request-Headers

其中Access-Control-Allow-Headers一般包含基本欄位,如Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma;對於其他欄位,就必須在Access-Control-Expose-Headers裡面指定。

CORS分類

瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)
1.簡單請求
只要同時滿足以下兩大條件,就屬於簡單請求

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

凡是不同時滿足上面兩個條件,就屬於非簡單請求。
2.非簡單請求


非簡單請求是那種對伺服器有特殊要求的請求,比如請求方法是PUT、DELETE或OPTIONS,或者Content-Type欄位的型別是application/json。

跨域處理方式

為什麼要講簡單請求和非簡單請求呢?因為瀏覽器對對這兩種請求的處理,是不一樣的。
1.簡單請求
對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭資訊之中,增加一個Origin欄位。
處理如下:

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';

在nginx上經以上配置,一般能夠解決簡單請求的跨域處理。
CORS請求預設不傳送Cookie和HTTP認證資訊。但是如果要把Cookie發到伺服器,要伺服器同意,指定Access-Control-Allow-Credentials欄位。

add_header 'Access-Control-Allow-Credentials' 'true';

需要注意的是,如果要傳送Cookie,Access-Control-Allow-Origin就不能設為星號,必須指定明確的、與請求網頁一致的域名。
2.非簡單請求
(1)非簡單請求的CORS請求,會在正式通訊之前,增加一次HTTP查詢請求,稱為”預檢”請求(preflight),預撿的請求方法是OPTIONS。瀏覽器先詢問伺服器,當前網頁所在的域名是否在伺服器的許可名單之中,以及可以使用哪些HTTP動詞和頭資訊欄位。
因此我們可以在瀏覽器的開發者工具中檢視頭資訊,若頭資訊中有OPTIONS方法,說明此次CORS請求是非簡單請求,需要在nginx中新增頭:

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';

此時雖然我們已經添加了所有的Methods方法,但是預檢請求仍不會通過,因此此時nginx對OPTIONS方法返回”405 Method Not Allowed”或者403。我們需要在nginx對OPTIONS方法進行處理,如下:

if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    add_header 'Access-Control-Allow-Headers' 'Content-Type';
    return 200;
}
或
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
#在location處新增以下內容
if ($request_method = 'OPTIONS') {
    return 200;
}

我們在nginx上將OPTIONS方法返回200,而不是405或403。

(2)伺服器經過以上設定通過了”預檢”請求,以後每次瀏覽器正常的CORS請求,就都跟簡單請求一樣,會有一個Origin頭資訊欄位。

總結

以前完全忽略了CORS的簡單請求和非簡單請求,以為陪著了Origins和Method就可以了。通過此次瞭解,其實之前文件有提到過,但是沒有沉下心仔細研究。
在此特別引用一下兩篇博文:
Nginx通過CORS實現跨域
跨域資源共享 CORS 詳解