文本討論關於接口開發中的跨域 CORS。html
CORS是一種瀏覽器協議,源於HTTP 請求的安全策略,在這個體系中的關鍵詞有,同源策略,XMLHttpRequest,Ajax,和先後端分離。尤爲是在目前業界先後端分離的大趨勢下,跨域是一種常見的先後端開發通信(communicate)方式。html5
The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail.以上一段話參考 Cross-domain Ajax with Cross-Origin Resource Sharing/,主要含義是說CORS的核心思想是經過HTTP請求頭通信,使得客戶端和服務器端彼此決定請求和響應是否被成功接受。nginx
Using CORS這裏有一篇關於跨域技術的完整闡述,感興趣的能夠閱讀。git
CORS 協議的實現須要客戶端和服務器端配合協做完成。也就是咱們一般所說的跨域設置。
The browser adds some additional headers, and sometimes makes additional requests, during a CORS request on behalf of the clientgithub
瀏覽器將CORS請求分紅兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。web
Microsoft API設計指導 中這麼一段關於跨域的描述ajax
8.1.1. Avoiding preflightjson
Because the CORS protocol can trigger preflight requests that add additional round trips to the server, performance-critical apps might be interested in avoiding them. The spirit behind CORS is to avoid preflight for any simple cross-domain requests that old non-CORS-capable browsers were able to make. All other requests require preflight.後端
A request is "simple" and avoids preflight if its method is GET, HEAD or POST, and if it doesn't contain any request headers besides Accept, Accept-Language and Content-Language. For POST requests, the Content-Type header is also allowed, but only if its value is "application/x-www-form-urlencoded," "multipart/form-data" or "text/plain." For any other headers or values, a preflight request will happen.api
The spirit behind CORS is to avoid preflight for any simple cross-domain requests that old non-CORS-capable browsers were able to make
咱們提煉出簡單請求的判斷標準
1 )GET, HEAD or POST 三種請求
2) 不增長任何額外的請求頭
3) POST 請求容許三種Content—Type: "application/x-www-form-urlencoded," "multipart/form-data" or "text/plain.
不符合簡單請求的,均屬於非簡單請求。這麼看來咱們平時常常使用的
Content-Type: application/json
顯然是一種非簡單請求頭。
對於非簡單請求,CORS 機制會自動觸發瀏覽器首先進行 preflight(一個 OPTIONS 請求), 該請求成功後纔會發送真正的請求。這裏的 preflight 也能夠被翻譯爲(預檢)請求。
像上文中所說那樣, 增長了自定義字段後,跨域請求就變成了一種帶有 preflight 的非簡單請求,所以會有下面的一種理解。
Access-Control-Allow-Headers是 preflight 請求中用來標識真正請求將會包含哪些頭部字段,也就是下文中的自定義頭部。這種方式是服務器端安全防範的一種。
這個設置是關因而否支持Cookies的
xhr.withCredentials = true; Access-Control-Allow-Credentials: true
//Access-Control-Allow-Origin:* public $arr_acao = [ '*' ]; //Access-Control-Allow-Methods public $arr_acam = [ 'POST', 'PUT', 'GET', 'DELETE', 'OPTIONS' ]; //Access-Control-Allow-Headers public $arr_acah = [ 'token', 'app-key', 'content-type', ]; header('Access-Control-Allow-Origin: '.implode(',', $this->arr_acao)); header('Access-Control-Allow-Methods: '.implode(',', $this->arr_acam)); header('Access-Control-Allow-Headers: '.implode(',', $this->arr_acah)); header("Access-Control-Max-Age: 86400"); if ($req->isOptions) { $code = "202"; $message = "Accepted"; header("HTTP/1.1 ".$code." ".$message); exit(); }
經過 Access-Control-Allow-Headers 設置自定義字段的方式,是一種安全策略,服務端要求請求頭必須攜帶 'token', 'app-key','content-type'三個屬性字段,缺一不可,不然請求不能達成。
origin 'http://xx.cn' has been blocked by CORS policy: Request header field timestamp is not allowed by Access-Control-Allow-Headers in preflight response.
location ~* \.(eot|ttf|woff|woff2|svg)$ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; }
以上設置的前提是Nginix 開啓了模塊 ngx_http_headers_module
# # 用於nginx的開放式CORS配置 # location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # 自定義標題和標題各類瀏覽器*應該*能夠,但不是 # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # # 有效期爲 # add_header 'Access-Control-Max-Age' 22000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; }
Nginx中跨域,應用程序與web服務器存在耦合,增長了應用程序部署和擴展的複雜性,按需使用。
本文主要介紹了CROS的基本分類和常見的實現方案,對於同源策略,XMLHttpRequest請求等基礎知識被沒有過多涉及。簡單請求和非簡單請求的分類是重點。理解了這一點,就能理解什麼場景瀏覽器會發起預檢請求,並回復對應的響應。
咱們常說跨域設置是客戶端和服務器端一塊兒配合的結果,官方協議更傾向於讓開發者對於跨域無感知,而瀏覽器與後端服務的交互和相互信任是核心。
I want to add CORS support to my server
Using CORS