CORS——一種新的跨域解決方案

一種新的跨域解決方案:CORS(跨域資源共享)javascript

它是W3c的工做草案,定義了在跨域訪問資源時瀏覽器和服務器之間如何通訊。html

CORS背後的基本思想是使用 自定義的HTTP頭部容許瀏覽器和服務器相互瞭解對方,從而決定請求或響應成功與否。java

CORS須要瀏覽器和服務器同時支持。目前,全部主流瀏覽器都支持該功能,IE瀏覽器不能低於IE8(IE10提供了對規範的完整支持;但在IE八、IE9中,CORS機制是藉由XDomainRequest對象完成的)。編程

整個CORS通訊過程,都是瀏覽器自動完成,不須要用戶參與。對於開發者來講,CORS通訊與同源的AJAX通訊沒有差異,代碼徹底同樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感受。跨域

所以,實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨域通訊。瀏覽器

服務器端對於CORS的支持,主要就是經過設置Access-Control-Allow-Origin來進行的。服務器

簡單請求 和 複雜請求

CORS能夠分紅兩種:app

  • 簡單請求
  • 複雜請求

什麼是簡單請求 和複雜請求

一個簡單的請求大體以下:編程語言

HTTP方法是下列之一函數

  • HEAD
  • GET
  • POST

HTTP頭包含

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type,但僅能是下列之一

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

任何不符合上述要求的,都可以看作 複雜請求。爲何要區分簡單請求和複雜請求,由於瀏覽器對這兩種請求的處理方式是有區別的。對於複雜請求,瀏覽器跟服務器之間會有一次「預請求」。

先挖個坑,暫且不解釋預請求是什麼。

先說簡單請求:
對於簡單請求,瀏覽器直接發出CORS請求。具體來講,就是在頭信息之中,增長一個Origin字段。

下面是一個例子,瀏覽器發現此次跨源AJAX請求是簡單請求,就自動在頭信息之中,添加一個Origin字段。

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Host: localhost:3000
Origin: http://localhost
Referer: http://localhost/
User-Agent: Mozilla/5.0 (Macintosh; .......

上面的頭信息中,Origin字段用來講明,本次請求來自哪一個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否贊成此次請求。

若是Origin指定的源,不在許可範圍內,服務器會返回一個正常的HTTP迴應。瀏覽器發現,這個迴應的頭信息沒有包含Access-Control-Allow-Origin字段(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。注意,這種錯誤沒法經過狀態碼識別,由於HTTP迴應的狀態碼有多是200。

若是Origin指定的域名在許可範圍內,服務器返回的響應,會多出幾個頭信息字段。

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的頭信息之中,有三個與CORS請求相關的字段,都以Access-Control-開頭。

  1. Access-Control-Allow-Origin:該字段是必須的。它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任意域名的請求。
  2. Access-Control-Allow-Credentials:該字段可選。它的值是一個布爾值,表示是否容許發送Cookie。默認狀況下,Cookie不包括在CORS請求之中。設爲true,即表示服務器明確許可,Cookie能夠包含在請求中,一塊兒發給服務器。這個值也只能設爲true,若是服務器不要瀏覽器發送Cookie,刪除該字段便可。
  3. Access-Control-Expose-Headers:該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。若是想拿到其餘字段,就必須在Access-Control-Expose-Headers裏面指定。上面的例子指定,getResponseHeader('FooBar')能夠返回FooBar字段的值。
var http = require('http');

http.createServer(function (req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.write('hello world ~~~');
    res.end();
}).listen(3000);

什麼是「預請求」?
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使用哪些HTTP動詞和頭信息字段。只有獲得確定答覆,瀏覽器纔會發出正式的XMLHttpRequest請求,不然就報錯。

在衆多的跨域方案中,JSONP跟CORS在使用方式上比較接近。
CORS與JSONP相比,更爲先進、方便和可靠。

  1. JSONP只能實現GET請求,而CORS支持全部類型的HTTP請求。
  2. 使用CORS,開發者可使用普通的XMLHttpRequest發起請求和得到數據,比起JSONP有更好的錯誤處理。
  3. JSONP主要被老的瀏覽器支持,它們每每不支持CORS;而絕大多數現代瀏覽器都已經支持了CORS,包括IE8。而服務端可經過任何編程語言來實現,只要能將CORS響應頭寫入response對象中便可。
相關文章
相關標籤/搜索