上篇文章介紹了幾種經常使用的跨域方法:經常使用跨域方法總結,本片爲上一篇的補充,對比較重要的Cross Origin Resource Sharing
詳細介紹。html
出於安全緣由,從腳本內發起的跨源HTTP請求會受到必定限制。 例如,XMLHttpRequest和Fetch API遵循同源策略。 這意味着使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非使用CORS頭文件。跨域資源共享標準新增了一組 HTTP 首部字段,容許服務器聲明哪些源站有權限訪問哪些資源。另外,規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法(特別是 GET 之外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否容許該跨域請求。服務器確認容許以後,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也能夠通知客戶端,是否須要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。前端
若要利用CORS來進行跨域獲取資源,還須要服務端的配合。
這裏分爲兩種場景:簡單請求和非簡單請求segmentfault
什麼樣的請求才屬於簡單請求呢,讓咱們先來看MDN的一段定義跨域
必須使用下列方法中的一種:瀏覽器
請求首部字段不能超出如下幾種緩存
Content-Type 的值僅限於下列三者之一:安全
同時知足以上5種條件,則能夠視爲簡單請求。
先跑例子吧。
首先上服務端代碼:服務器
var http = require('http'); http.createServer(function (req, res) { res.setHeader("Access-Control-Allow-Origin","*"); res.end(JSON.stringify({'success':true,msg:'今天,我就是要用cors來跨域'+Math.random()})); }).listen(8080)
很簡單有沒有,Access-Control-Allow-Origin
:限制發起跨域請求的來源,*表示不限制
(請求首部字段下文詳細介紹)
前端代碼:app
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var xhr = new XMLHttpRequest() xhr.open('get', 'http://localhost:8080') xhr.onreadystatechange = function () { if (xhr.readyState === 4) { console.log(JSON.parse(xhr.responseText)) } } xhr.send() </script> </body> </html>
結果確定是請求成功啦cors
簡單來講吧,不符合簡單請求的都是非簡單請求(怎麼感受這麼大白話呢- -)詳見CORS
與前述簡單請求不一樣,「非簡單請求」要求必須首先使用 OPTIONS 方法發起一個預檢請求到服務器,以獲知服務器是否容許該實際請求。"預檢請求「的使用,能夠避免跨域請求對服務器的用戶數據產生未預期的影響。
仍是先上代碼
服務端:
var http = require('http'); http.createServer(function (req, res) { res.setHeader("Access-Control-Allow-Origin","*"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); res.setHeader("Access-Control-Allow-Methods","PUT,GET,POST,DELETE,OPTIONS"); res.end(JSON.stringify({'success':true,msg:'今天,我就是要用cors來跨域'+Math.random()})); }).listen(8080) console.log('正在監聽8080')
Access-Control-Allow-Headers
::預檢請求響應的首部字段定義了實際請求中容許攜帶的額外的首部字段。Access-Control-Allow-Methods
:預檢請求響應的首部字段定義了實際請求所容許使用的 HTTP 方法。(筆者作實驗的遇到了一個小插曲,simple method會不受此限制,詳見爲何 Access-Control-Allow-Methods 不起做用?)
前端
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var xhr = new XMLHttpRequest() xhr.open('get', 'http://localhost:8080') xhr.setRequestHeader('Content-type','text/html') // 添加了非簡單請求的Content-Type xhr.onreadystatechange = function () { if (xhr.readyState === 4) { console.log(JSON.parse(xhr.responseText)) } } xhr.send() </script> </body> </html>
結果確定也是請求成功啦。
這裏有一點要注意的地方,這裏仍是說一下吧
通常而言,對於跨域 XMLHttpRequest 或 Fetch 請求,瀏覽器不會發送身份憑證信息。若是要發送憑證信息,須要設置 XMLHttpRequest 的某個特殊標誌位。
也就是前端請求的時候:xhr.withCredentials = true
對於附帶身份憑證的請求,服務器不得設置 Access-Control-Allow-Origin 的值爲「 」。若請求的首部中攜帶了 Cookie 信息,若是 Access-Control-Allow-Origin 的值爲「」,請求將會失敗。
這塊內容MDN已經很詳細了,爲了方便閱讀,筆者仍是整理過來了。
請注意,這些首部字段無須手動設置。 當開發者使用 XMLHttpRequest 對象發起跨域請求時,它們已經被設置就緒。Origin
首部字段代表預檢請求或實際請求的源站。(注意,不論是否爲跨域請求,ORIGIN 字段老是被髮送。)Access-Control-Request-Method
,用於預檢請求,表示實際請求的方法Access-Control-Request-Headers
,用於預檢請求,表示實際請求中添加的額外的首部字段
Access-Control-Allow-Method
,預檢請求的響應,表示容許的接下來的實際請求的方法。(筆者作實驗的遇到了一個小插曲,simple method會不受此限制,詳見爲何 Access-Control-Allow-Methods 不起做用?)Access-Control-Allow-Origin
,指定了容許訪問該資源的外域 URI。對於不須要攜帶身份憑證的請求,服務器能夠指定該字段的值爲通配符,表示容許來自全部域的請求。Access-Control-Allow-Credentials
,當瀏覽器(好比xhr)的credentials設置爲true時是否容許瀏覽器讀取response的內容。當用在對preflight預檢測請求的響應中時,它指定了實際的請求是否可使用credentials(若是請求credentials爲true時,該響應首部字段須要設置爲true)。Access-Control-Allow-Headers
,預檢請求的響應,表示容許的接下來的實際請求的額外的首部字段。預檢請求的響應。其指明瞭實際請求中容許攜帶的首部字段。Access-Control-Expose-Headers
,在跨域訪問時,XMLHttpRequest對象的getResponseHeader()方法只能拿到一些最基本的響應頭,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,若是要訪問其餘頭,則須要服務器設置本響應頭。Access-Control-Max-Age
:指定了預檢請求的結果可以被緩存多久
到這裏筆者對跨域算是比較熟悉了,感謝各位的閱讀,若有不對的地方,歡迎你們批評指正。
還有,最好是對每一個例子都有實際運行理解更深入哦。