欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

利用CORS實(shí)現(xiàn)跨域請(qǐng)求

系統(tǒng) 1830 0

跨域請(qǐng)求一直是網(wǎng)頁(yè)編程中的一個(gè)難題,在過(guò)去,絕大多數(shù)人都傾向于使用 JSONP 來(lái)解決這一問(wèn)題。不過(guò)現(xiàn)在,我們可以考慮一下W3C中一項(xiàng)新的特性——CORS(Cross-Origin Resource Sharing)了。

?

本文的所有代碼均來(lái)自 http://www.html5rocks.com/en/tutorials/cors/ ,如果您對(duì)其中的任何技術(shù)細(xì)節(jié)存在疑問(wèn),請(qǐng)以原文為準(zhǔn)。

客戶端

創(chuàng)建 XmlHttpRequest 對(duì)象

對(duì)于CORS,Chrome、FireFox以及Safari,需要使用 XmlHttpRequest2 對(duì)象;而對(duì)于IE,則需要使用 XDomainRequest ;Opera目前還不支持這一特性,但很快就會(huì)支持。

因此,在對(duì)象的創(chuàng)建上,我們不得不首先針對(duì)不同的瀏覽器而進(jìn)行一下預(yù)處理:

    function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {

    // "withCredentials"屬性是XMLHTTPRequest2中獨(dú)有的
    xhr.open(method, url, true);

  } else if (typeof XDomainRequest != "undefined") {

    // 檢測(cè)是否XDomainRequest可用
    xhr = new XDomainRequest();
    xhr.open(method, url);

  } else {

    // 看起來(lái)CORS根本不被支持
    xhr = null;

  }
  return xhr;
}

var xhr = createCORSRequest('GET', url);
if (!xhr) {
  throw new Error('CORS not supported');
}
  
?

事件處理

原先的 XmlHttpRequest 對(duì)象僅僅只有一個(gè)事件—— onreadystatechange ,用以通知所有的事件,而現(xiàn)在,我們除了這個(gè)事件之外又多了很多新的。

事件 說(shuō)明
onloadstart* 當(dāng)請(qǐng)求發(fā)生時(shí)觸發(fā)
onprogress 讀取及發(fā)送數(shù)據(jù)時(shí)觸發(fā)
onabort* 當(dāng)請(qǐng)求被中止時(shí)觸發(fā),如使用abort()方法
onerror 當(dāng)請(qǐng)求失敗時(shí)觸發(fā)
onload 當(dāng)請(qǐng)求成功時(shí)觸發(fā)
ontimeout 當(dāng)調(diào)用者設(shè)定的超時(shí)時(shí)間已過(guò)而仍未成功時(shí)觸發(fā)
onloadend* 請(qǐng)求結(jié)束時(shí)觸發(fā)(無(wú)論成功與否)

注:帶星號(hào)的表示IE的 XDomainRequest 仍不支持。
數(shù)據(jù)來(lái)自 http://www.w3.org/TR/XMLHttpRequest2/#events

絕大多數(shù)情況下,我們只需要和 onload onerror 打交道,就像下面這樣:

    xhr.onload = function() {
 var responseText = xhr.responseText;
 console.log(responseText);
 // 繼續(xù)其它代碼
};

xhr.onerror = function() {
  console.log('There was an error!');
};
  
? 這兒有一點(diǎn)小異樣。盡管我們可以通過(guò) onerror 得知請(qǐng)求發(fā)生了錯(cuò)誤,但在事件處理時(shí),我們無(wú)法從代碼上獲知失敗的任何原因。比如,F(xiàn)ireFox在失敗時(shí)將 responseText 置空并返回一個(gè)0值作為狀態(tài),這當(dāng)中并不包含任何錯(cuò)誤的具體情況。

withCredentials

標(biāo)準(zhǔn)的CORS請(qǐng)求不對(duì)cookies做任何事情,既不發(fā)送也不改變。如果希望改變這一情況,就需要將 withCredentials 設(shè)置為 true

    xhr.withCredentials = true;
  
? 另外,服務(wù)端在處理這一請(qǐng)求時(shí),也需要將 Access-Control-Allow-Credentials 設(shè)置為 true 。這一點(diǎn)我們稍后來(lái)說(shuō)。

withCredentials 屬性使得請(qǐng)求包含了遠(yuǎn)程域的所有cookies,但值得注意的是,這些cookies仍舊遵守“同域”的準(zhǔn)則,因此從代碼上你并不能從 document.cookies 或者回應(yīng)HTTP頭當(dāng)中進(jìn)行讀取。

發(fā)送請(qǐng)求

請(qǐng)求通過(guò)一個(gè)簡(jiǎn)單的 send() 方法進(jìn)行發(fā)送,如果請(qǐng)求當(dāng)中需要包含任何內(nèi)容,也只需要將其作為一個(gè)參數(shù)傳遞給 send() 即可。一旦服務(wù)端配置OK,那么你將只需要處理后續(xù)的 onload 事件,這正像我們平時(shí)所熟悉的XHR一樣。

來(lái)看一段完整的小代碼:

    // 創(chuàng)建XHR對(duì)象
function createCORSRequest(method, url) {
  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    // 針對(duì)Chrome/Safari/Firefox.
    xhr.open(method, url, true);
  } else if (typeof XDomainRequest != "undefined") {
    // 針對(duì)IE
    xhr = new XDomainRequest();
    xhr.open(method, url);
  } else {
    // 不支持CORS
    xhr = null;
  }
  return xhr;
}

// 輔助函數(shù),用于解析返回的內(nèi)容
function getTitle(text) {
  return text.match('<title>(.*)?</title>')[1];
}

// 發(fā)送CORS請(qǐng)求
function makeCorsRequest() {
  // bibliographica.org是支持CORS的
  var url = 'http://bibliographica.org/';

  var xhr = createCORSRequest('GET', url);
  if (!xhr) {
    alert('CORS not supported');
    return;
  }

  // 回應(yīng)處理
  xhr.onload = function() {
    var text = xhr.responseText;
    var title = getTitle(text);
    alert('Response from CORS request to ' + url + ': ' + title);
  };

  xhr.onerror = function() {
    alert('Woops, there was an error making the request.');
  };

  xhr.send();
}
  
?

服務(wù)端

一個(gè)CORS請(qǐng)求可能包含多個(gè)HTTP頭,甚至有多個(gè)請(qǐng)求實(shí)際發(fā)送,這對(duì)于客戶端的開(kāi)發(fā)者來(lái)說(shuō)通常是透明的。因?yàn)闉g覽器已經(jīng)負(fù)責(zé)實(shí)現(xiàn)了CORS最關(guān)鍵的部分;但是服務(wù)端的后臺(tái)腳本則需要我們自己進(jìn)行處理,因此我們還需要了解到服務(wù)端到底從瀏覽器那里收到了怎樣的內(nèi)容。

先來(lái)看看流程圖吧。

利用CORS實(shí)現(xiàn)跨域請(qǐng)求

CORS分類(lèi)

CORS可以分成兩種:

  • 簡(jiǎn)單請(qǐng)求
  • 復(fù)雜請(qǐng)求

一個(gè)簡(jiǎn)單的請(qǐng)求大致如下:

  • 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

任何一個(gè)不滿足上述要求的請(qǐng)求,即被認(rèn)為是復(fù)雜請(qǐng)求。一個(gè)復(fù)雜請(qǐng)求不僅有包含通信內(nèi)容的請(qǐng)求,同時(shí)也包含預(yù)請(qǐng)求(preflight request)。

簡(jiǎn)單請(qǐng)求

為了搞清楚復(fù)雜請(qǐng)求與簡(jiǎn)單請(qǐng)求有何區(qū)別,我們首先來(lái)看看簡(jiǎn)單請(qǐng)求是怎樣處理的。

JavaScript:

    var url = 'http://alice.com/cors';
var xhr = createCORSRequest('GET', url);
xhr.send();
  

? HTTP請(qǐng)求:

    GET /cors HTTP/1.1
Origin: http://api.alice.com
Host: api.bob.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
  
? 簡(jiǎn)單請(qǐng)求的發(fā)送從代碼上來(lái)看和普通的XHR沒(méi)太大區(qū)別,但是HTTP頭當(dāng)中要求總是包含一個(gè)域(Origin)的信息。該域包含協(xié)議名、地址以及一個(gè)可選的端口。不過(guò)這一項(xiàng)實(shí)際上由瀏覽器代為發(fā)送,并不是開(kāi)發(fā)者代碼可以觸及到的。

HTTP回應(yīng):

    Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
  
? 在回應(yīng)中,COR相關(guān)的項(xiàng)目全都是以“ Access-Control- ”作為前綴的,其意義分列如下:
  • Access-Control-Allow-Origin (必含)- 不可省略,否則請(qǐng)求按失敗處理。該項(xiàng)控制數(shù)據(jù)的可見(jiàn)范圍,如果希望數(shù)據(jù)對(duì)任何人都可見(jiàn),可以填寫(xiě)“*”。
  • Access-Control-Allow-Credentials (可選) – 該項(xiàng)標(biāo)志著請(qǐng)求當(dāng)中是否包含cookies信息,只有一個(gè)可選值: true (必為小寫(xiě))。如果不包含cookies,請(qǐng)略去該項(xiàng),而不是填寫(xiě) false 。這一項(xiàng)與 XmlHttpRequest2 對(duì)象當(dāng)中的 withCredentials 屬性應(yīng)保持一致,即 withCredentials true 時(shí)該項(xiàng)也為 true withCredentials false 時(shí),省略該項(xiàng)不寫(xiě)。反之則導(dǎo)致請(qǐng)求失敗。
  • Access-Control-Expose-Headers (可選) – 該項(xiàng)確定 XmlHttpRequest2 對(duì)象當(dāng)中 getResponseHeader() 方法所能獲得的額外信息。通常情況下, getResponseHeader() 方法只能獲得如下的信息:
    • Cache-Control
    • Content-Language
    • Content-Type
    • Expires
    • Last-Modified
    • Pragma

    當(dāng)你需要訪問(wèn)額外的信息時(shí),就需要在這一項(xiàng)當(dāng)中填寫(xiě)并以逗號(hào)進(jìn)行分隔。不過(guò)目前瀏覽器對(duì)這一項(xiàng)的實(shí)現(xiàn)仍然有一些問(wèn)題,具體請(qǐng)見(jiàn)文尾的BUG一節(jié)。

復(fù)雜請(qǐng)求

如果僅僅是簡(jiǎn)單請(qǐng)求,那么即便不用CORS也沒(méi)有什么大不了,但CORS的復(fù)雜請(qǐng)求就令CORS顯得更加有用了。簡(jiǎn)單來(lái)說(shuō),任何不滿足上述簡(jiǎn)單請(qǐng)求要求的請(qǐng)求,都屬于復(fù)雜請(qǐng)求。比如說(shuō)你需要發(fā)送 PUT DELETE 等HTTP動(dòng)作,或者發(fā)送 Content-Type: application/json 的內(nèi)容。

復(fù)雜請(qǐng)求表面上看起來(lái)和簡(jiǎn)單請(qǐng)求使用上差不多,但實(shí)際上瀏覽器發(fā)送了不止一個(gè)請(qǐng)求。其中最先發(fā)送的是一種“預(yù)請(qǐng)求”,此時(shí)作為服務(wù)端,也需要返回“預(yù)回應(yīng)”作為響應(yīng)。預(yù)請(qǐng)求實(shí)際上是對(duì)服務(wù)端的一種權(quán)限請(qǐng)求,只有當(dāng)預(yù)請(qǐng)求成功返回,實(shí)際請(qǐng)求才開(kāi)始執(zhí)行。

JavaScript:

    var url = 'http://alice.com/cors';
var xhr = createCORSRequest('PUT', url);
xhr.setRequestHeader(
    'X-Custom-Header', 'value');
xhr.send();
  

? 預(yù)請(qǐng)求:

    OPTIONS /cors HTTP/1.1
Origin: http://api.alice.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.bob.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
  
? 預(yù)請(qǐng)求以 OPTIONS 形式發(fā)送,當(dāng)中同樣包含域,并且還包含了兩項(xiàng)CORS特有的內(nèi)容:
  • Access-Control-Request-Method ?– 該項(xiàng)內(nèi)容是實(shí)際請(qǐng)求的種類(lèi),可以是GET、POST之類(lèi)的簡(jiǎn)單請(qǐng)求,也可以是 PUT DELETE 等等。
  • Access-Control-Request-Headers ?– 該項(xiàng)是一個(gè)以逗號(hào)分隔的列表,當(dāng)中是復(fù)雜請(qǐng)求所使用的頭部。

顯而易見(jiàn),這個(gè)預(yù)請(qǐng)求實(shí)際上就是在為之后的實(shí)際請(qǐng)求發(fā)送一個(gè)權(quán)限請(qǐng)求,在預(yù)回應(yīng)返回的內(nèi)容當(dāng)中,服務(wù)端應(yīng)當(dāng)對(duì)這兩項(xiàng)進(jìn)行回復(fù),以讓瀏覽器確定請(qǐng)求是否能夠成功完成。例如,剛才的預(yù)請(qǐng)求可能獲得服務(wù)端如下的回應(yīng):

    Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
  
? 來(lái)看看預(yù)回應(yīng)當(dāng)中可能的項(xiàng)目:
  • Access-Control-Allow-Origin (必含) – 和簡(jiǎn)單請(qǐng)求一樣的,必須包含一個(gè)域。
  • Access-Control-Allow-Methods (必含) – 這是對(duì)預(yù)請(qǐng)求當(dāng)中 Access-Control-Request-Method 的回復(fù),這一回復(fù)將是一個(gè)以逗號(hào)分隔的列表。盡管客戶端或許只請(qǐng)求某一方法,但服務(wù)端仍然可以返回所有允許的方法,以便客戶端將其緩存。
  • Access-Control-Allow-Headers (當(dāng)預(yù)請(qǐng)求中包含 Access-Control-Request-Headers 時(shí)必須包含) – 這是對(duì)預(yù)請(qǐng)求當(dāng)中 Access-Control-Request-Headers 的回復(fù),和上面一樣是以逗號(hào)分隔的列表,可以返回所有支持的頭部。
  • Access-Control-Allow-Credentials (可選) – 和簡(jiǎn)單請(qǐng)求當(dāng)中作用相同。
  • Access-Control-Max-Age (可選) – 以秒為單位的緩存時(shí)間。預(yù)請(qǐng)求的的發(fā)送并非免費(fèi)午餐,允許時(shí)應(yīng)當(dāng)盡可能緩存。

一旦預(yù)回應(yīng)如期而至,所請(qǐng)求的權(quán)限也都已滿足,則實(shí)際請(qǐng)求開(kāi)始發(fā)送。

實(shí)際請(qǐng)求:

    PUT /cors HTTP/1.1
Origin: http://api.alice.com
Host: api.bob.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
  

? 實(shí)際回應(yīng):

    Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8
  

? 如果預(yù)請(qǐng)求所要求的權(quán)限服務(wù)端不允許,那么服務(wù)端可以直接返回一個(gè)普通的HTTP回應(yīng),比如:

    // ERROR - No CORS headers, this is an invalid request!
Content-Type: text/html; charset=utf-8
  

? 這樣的返回因?yàn)椴环峡蛻舳说男枨螅蚨蛻舳藭?huì)直接將請(qǐng)求以失敗計(jì),雖然不是很美氣,不過(guò)正符合我們的實(shí)際。此時(shí)如果客戶端的 onerror 事件有監(jiān)聽(tīng)函數(shù),那么將會(huì)觸發(fā),而瀏覽器的console窗口也會(huì)輸出:

    XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
  
? 不過(guò)很可惜,瀏覽器并不會(huì)給出詳細(xì)的錯(cuò)誤情況,僅僅是告知我們出錯(cuò)而已。

安全問(wèn)題

跨域請(qǐng)求始終是網(wǎng)頁(yè)安全中一個(gè)比較頭疼的問(wèn)題,CORS提供了一種跨域請(qǐng)求方案,但沒(méi)有為安全訪問(wèn)提供足夠的保障機(jī)制,如果你需要信息的絕對(duì)安全,不要依賴CORS當(dāng)中的權(quán)限制度,應(yīng)當(dāng)使用更多其它的措施來(lái)保障,比如OAuth2。

已知問(wèn)題

CORS是W3C中一項(xiàng)較“新”的方案,以至于各大網(wǎng)頁(yè)解析引擎還沒(méi)有對(duì)其進(jìn)行完美的實(shí)現(xiàn)。下面是截至2011年11月13日時(shí)的已知問(wèn)題:

  • getAllResponseHeaders() 方法無(wú)法獲取 Access-Control-Expose-Headers 當(dāng)中要求的信息。在Chrome/Safari當(dāng)中,僅僅只有簡(jiǎn)單的頭部能夠讀取,其他無(wú)法獲取;在FireFox當(dāng)中,無(wú)法獲得任何信息。( FireFox Bugzilla / Webkit Bugzilla
  • 在Safari當(dāng)中,使用 GET POST 方法的復(fù)雜請(qǐng)求發(fā)送時(shí)沒(méi)有發(fā)送預(yù)請(qǐng)求的環(huán)節(jié)。
  • onerror 觸發(fā)時(shí) statusText 獲取不到任何內(nèi)容。
  • Opera截至11.60仍舊不支持CORS,但在12當(dāng)中會(huì)支持( Opera Core Concerns – CORS goes mainline )。

閱讀更多

[ 轉(zhuǎn)自 : http://newhtml.net/using-cors/ ]

利用CORS實(shí)現(xiàn)跨域請(qǐng)求


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 日韩三级视频 | 欧美激情久久久 | 国产区免费在线观看 | 日韩欧美亚洲一区 | 亚洲日本中文字幕天天更新 | 成人影视大全 | 97日日摸天天碰免费视频 | 久久伦理中文字幕 | 国产福利视频在线 | 亚洲综合色站 | 一区二区三区久久 | 91精品国产日韩91久久久久久360 | 91大神精品长腿在线观看网站 | 欧美一a一片一级一片 | 亚洲精品国产a久久久久久 亚洲国产精品第一页 | 意大利av在线 | 一区二区免费 | 免费无码毛片一区二区A片 成人18网站 | 日本精品一区二区三区在线 | 亚洲伊人成综合网 | 明明电影高清在线观看 | a视频在线免费观看 | 久久久精品在线观看 | 免费无码毛片一区二区A片 成人18网站 | 看一天影院 理论片 | 久久网亚洲 | 色一欲一性一乱一区二区三区 | 欧美在线精品一区二区在线观看 | 国产一区不卡 | 国产一有一级毛片视频 | 亚洲人人草| 国产精品久久久久久久久久久久久 | 看片国产 | 欧美一区二区三区在线看 | 一级黄色大毛片 | 午夜精品老牛av一区二区三区 | 天天摸天天碰天天碰 | 欧美激情一区二区三区中文字幕 | 一区视频 | 欧美精品一级 | 日本黄色福利视频 |