跨域的解決方案(二):CORS策略的介紹及實(shí)現(xiàn)

筆者博客

最近遇到了跨域問題,有很多種解決方案,本文主要對其中的CORS進(jìn)行演示,本文使用node編寫服務(wù)器端代碼進(jìn)行驗(yàn)證。在解決該問題的時(shí)候,順帶對cookie的操作進(jìn)行了一定的說明。

CORS簡介

CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務(wù)器,發(fā)出ajax請求,從而克服了AJAX只能同源使用的限制。
CORS依賴于服務(wù)器端的設(shè)定,只要在服務(wù)器端進(jìn)行了設(shè)置,就可以實(shí)現(xiàn)相應(yīng)的資源訪問。

CORS簡單服務(wù)器端實(shí)現(xiàn)

之前寫過一篇文章原生javascript封裝ajax,在該文章中,用面向?qū)ο蟮姆椒ê唵畏庋b了一個(gè)ajax通信類,同時(shí)建立了一個(gè)本地的服務(wù)器來進(jìn)行驗(yàn)證,(本文的代碼就基于上述代碼,倉庫在這里,服務(wù)器,客戶端的代碼都在里面,也有一些測試的說明。),事實(shí)上,在我進(jìn)行驗(yàn)證的時(shí)候就遇到了跨域的問題,因?yàn)楸镜剡\(yùn)行的頁面和本地運(yùn)行的服務(wù)器之間,不符合同源的策略,是不能進(jìn)行ajax通信的,我當(dāng)時(shí)采用的解決方案就是通過CORS方法在服務(wù)器端添加了Access-Control-Allow-字段實(shí)現(xiàn)了跨域通信。下面總結(jié)一下我在實(shí)際中的解決過程。

問題的出現(xiàn)

本地的頁面,直接打開html文件,而用node建立了一個(gè)localhost的服務(wù)器,在html中使用直接使用ajax向服務(wù)器端發(fā)送請求,服務(wù)器端沒有做CORS處理,此時(shí)瀏覽器會如下報(bào)錯(cuò):

problem.png

大致的意思就是服務(wù)器端沒有發(fā)現(xiàn)Access-Control-Allow-Origin字段,而本地的html的origin默認(rèn)是null(如果是在服務(wù)器上運(yùn)行,舉個(gè)例子,運(yùn)行在http://blog.xiaoboma.com/ajax-/,則origin是http://blog.xiaoboma.com,只包含協(xié)議和域名,不包含后面的url路由等路徑),因?yàn)椴黄ヅ?,所以不允許進(jìn)行通信,ajax請求失敗。值得注意的是,此時(shí)的通信失敗不能通過xhr.status判斷,需要通過xhr.onerror事件進(jìn)行相應(yīng)的處理。

解決方案

知道了問題,只需要在服務(wù)器端的header中增加Access-Control-Allow-Origin即可解決該問題,關(guān)鍵代碼如下:

res.writeHead(200,{'content-Type':'text/plain',"Access-Control-Allow-Origin":"*"});

此時(shí),ajax請求就可以正常發(fā)送,觀察調(diào)試工具(我使用的chrome)中的network一項(xiàng),就可以看到發(fā)送的數(shù)據(jù)以及收到的返回信息。

ajax.png

這張圖片主中的responseHeader和origin只要匹配,就可以進(jìn)行ajax請求。*表示任何origin都可以進(jìn)行訪問,事實(shí)上,在這里如果在服務(wù)器端將其設(shè)置成Access-Control-Allow-Origin":null也是可以進(jìn)行ajax通信的。

CORS小結(jié)

可以看出來,CORS的實(shí)現(xiàn)主要是服務(wù)器端的設(shè)定,origin也是瀏覽器自動添加,人為是不能修改的,所以只要在服務(wù)器端設(shè)置了Access-Control-Allow-Origin字段,就可以實(shí)現(xiàn)相應(yīng)網(wǎng)頁的跨域資源訪問,客戶端的ajax通信代碼不需要做任何的改動。

cookie的設(shè)定與發(fā)送

在設(shè)置Access-Control-Allow-Origin的時(shí)候不可避免的碰到了'Access-Control-Allow-Credentials'字段,按捺不住好奇,就搜索了這個(gè)字段,該字段只能設(shè)置為true,當(dāng)設(shè)置了true之后,允許客戶端通過ajax發(fā)送cookie,否則不接受客戶端發(fā)送的cookie,客戶端需要設(shè)置xhr.withCredentials = true;
在服務(wù)端的res.writeHead添加如下字段:

var time = new Date();
      var time = time.getTime() + 24*60*60*1000;//按ms計(jì)算,一天
      var time2 = new Date(time);
      var timeObj = time2.toGMTString();
      res.writeHead(200,{'content-Type':'text/plain',"Access-Control-Allow-Origin":null,
        'Set-Cookie':'myCookie="type=ninja",language="javascript";Expires = '+timeObj,'Access-Control-Allow-Credentials':true});
      res.end(util.inspect(url.parse(req.url, true)));//處理get請求,并將結(jié)果傳遞給客戶端

通過Access-Control-Allow-Credentials:true允許客戶端發(fā)送cookie至服務(wù)器端,通過Set-Cookie設(shè)置cookie內(nèi)容和過期時(shí)間(如果不設(shè)置過期時(shí)間,默認(rèn)頁面關(guān)閉)。這種狀態(tài)下,Access-Control-Allow-Origin不能為'*',否則會報(bào)錯(cuò),畢竟,不能讓每個(gè)網(wǎng)站都直接向服務(wù)器發(fā)送cookie,必須是經(jīng)過指定的域名才能,這里因?yàn)槭潜镜兀苯釉O(shè)置為null。此時(shí),在index.html中發(fā)送post請求,可以看到cookie信息。

cookie.png

cookie設(shè)置小結(jié)

要想通過客戶端發(fā)送cookie給服務(wù)器端,必須有服務(wù)器端支持。

  1. Access-Control-Allow-Credentials必須為true且只能為true
  2. Access-Control-Allow-Origin必須指定且不能為'*'
  3. 客戶端需要指定xhr.withCredentials = true;

需要注意的是,如果要發(fā)送Cookie,Access-Control-Allow-Origin就不能設(shè)為星號,必須指定明確的、與請求網(wǎng)頁一致的域名。同時(shí),Cookie依然遵循同源政策,只有用服務(wù)器域名設(shè)置的Cookie才會上傳,其他域名的Cookie并不會上傳,且(跨源)原網(wǎng)頁代碼中的document.cookie也無法讀取服務(wù)器域名下的Cookie。

參考文章

  1. 跨域資源共享 CORS 詳解
  2. node.js 操作Cookies
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容