跨域資源共用 (CORS) 是一種全球資訊網協會 (W3C) 規範(通常被認為是 HTML5 的一部分),它可讓 JavaScript 克服由瀏覽器施加的同域策略安全限制。所謂同域策略,就是 JavaScript 只能對包含網頁的同 一個域進行 AJAX 回調(其中,“域”就是主機名稱、協議和連接埠號碼的組合)。例如, http://foo.com 中某個網頁上的 JavaScript 無法對 http://bar.com(或 http://www.foo.com、 https://foo.com 或 http://foo.com:999 等)進行 AJAX 調用。
CORS 可讓伺服器指明允許哪些域對它們進行調用,從而放寬這種限制。CORS 是由瀏覽器強制執行的,並 且必須在伺服器上實現,而最新版本的 ASP.NET Web API 2 全面支援 CORS。通過 Web API 2,您可以對策略 進行配置以允許不同域的 JavaScript 用戶端訪問您的 API。
CORS 基本資料
由於 Web API 完全按照該規範來實現,因此,為了使用 Web API 中的新 CORS 功能,詳細瞭解 CORS 本 身將大有協助。這些詳細內容現在看起來可能都是理論之談,但對於以後瞭解 Web API 中的可用設定來說將 十分有用:在您調試 CORS 時,這些內容有助於您更快速地解決問題。
CORS 的一般機制是,當 JavaScript 嘗試進行跨域 AJAX 調用時,瀏覽器會通過在 HTTP 要求中發送標題 (如“Origin”)來“詢問”伺服器是否允許進行這樣的調用。伺服器通過在響應中返 回 HTTP 標題(如“Access-Control-Allow-Origin”)指明允許的操作。這種許可權檢查將針對客 戶端調用的每個不同 URL 進行,這就意味著不同的 URL 可以具有不同許可權。
除域之外,CORS 還可以讓伺服器指明允許使用的 HTTP 方法、用戶端可以發送的 HTTP 要求標題、用戶端 可以讀取的 HTTP 響應標題以及是否允許瀏覽器自動發送或接收憑據(Cookie 或授權標頭)。其他請求和響 應標題指明允許使用其中的哪些功能。圖 1 總結了這些標題(請注意,一些功能沒有在響 應中發送的標題,僅有響應)。
圖 1 CORS HTTP 標題
瀏覽器可通過兩種不同的方式向伺服器請求這些許可權:簡單 CORS 請求和預檢 CORS 請求。
簡單 CORS 請求。下面是簡單 CORS 請求的樣本:
POST http://localhost/WebApiCorsServer/Resources/ HTTP/1.1
Host: localhost
Accept: */*
Origin: http://localhost:55912
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
value1=foo&value2=5
響應如下:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: http://localhost:55912
Content-Length: 27
{"Value1":"foo","Value2":5}
該請求是從 http://localhost:55912 到 http://localhost 的跨域請求,而瀏覽器會在該請求中添加一 個“Origin”HTTP 標題以指示伺服器的調用域。 伺服器用“Access-Control-Allow- Origin”響應標題進行響應,指明允許使用此域。 瀏覽器強制執行伺服器的策略,而 JavaScript 將接 收其正常成功回調。
伺服器或者可以使用來自該請求的確切域值做出響應,或者可以使用指明允許使用任何域的 “*”值做出響應。 如果伺服器還未允許該調用域,則“Access-Control-Allow- Origin”標題會缺失,並會引起該調用 JavaScript 的錯誤回調。
請注意,進行簡單 CORS 請求時,仍會對伺服器進行調用。 如果您對 CORS 瞭解不深,可能會覺得奇怪, 但這種行為無異於瀏覽器已構造 <form> 元素並進行正常 POST 請求的情況。 CORS 不會阻止對伺服器 的調用;但它會阻止調用 JavaScript 接收結果。 如果您要阻止調用方調用伺服器,則需要在伺服器代碼中 實現某種授權(可能要使用 [Authorize] 授權篩選器屬性)。
前面的樣本稱為簡單 CORS 請求,因為來自用戶端的 AJAX 調用的類型或者是 GET,或者是 POST; Content-Type 是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 中的一 個;未發送任何其他請求標題。 如果 AJAX 調用是另一個 HTTP 方法,Content-Type 是某個其他值,或者客 戶端想要發送其他請求標題,則會將該請求視為預檢請求。 預檢請求的機制略有不同。
預檢 CORS 請求。如果 AJAX 調用不是簡單請求,則它需要一個預檢 CORS 請求,此請求只不過是一個發 送到伺服器以擷取許可權的附加 HTTP 要求。 此預檢請求由瀏覽器自動發出,並使用 OPTIONS HTTP 方法。 如 果伺服器成功響應該預檢請求並授予許可權,則瀏覽器將執行 JavaScript 正在嘗試執行的實際 AJAX 調用。
如果關心的是效能問題(以及何時出現效能問題),則瀏覽器可通過在預檢響應中包含 Access-Control- Max-Age 標題來緩衝此預檢請求的結果。 該值包含可對許可權進行緩衝的秒數。