問題概要
我從域 A 將 PDF.js 加載到 iframe 中,并以文件作為參數(shù)(服務(wù)器的完整路徑,這將返回 pdf 文檔)。PDF.js 將向域 B 的服務(wù)器創(chuàng)建一個(gè)請求,擴(kuò)展名為origin: domain A. 域 B 的服務(wù)器返回帶有 header 的 pdf 文檔Access-Control-Allow-Origin: domain A,到目前為止一切順利。
在我的網(wǎng)絡(luò)選項(xiàng)卡中,我看到對服務(wù)器的請求,該請求返回 200 狀態(tài) OK,但 PDF.js 拋出錯(cuò)誤Unexpected server response (0) while retrieving PDF <url>。
問題是,這里發(fā)生了什么,CORS 似乎沒問題,但我無法從 PDF.js 獲得更多信息,真正的原因是 PDF 無法加載。有沒有人遇到過同樣的情況?
問題解決
跨域Ajax與跨源資源共享
幾年前,Web 開發(fā)人員正在用頭撞 Ajax 的第一堵墻:同源策略。雖然我們驚嘆于跨瀏覽器支持所帶來的巨大進(jìn)步XMLHttpRequest對象,我們很快就抱怨沒有辦法從 JavaScript 向不同的域發(fā)出請求。每個(gè)人都在自己的網(wǎng)站上設(shè)置代理,這是一系列新的開放重定向問題的開始,作為繞過限制的一種方法。盡管開發(fā)人員正在使用服務(wù)器端代理以及其他技術(shù)來解決此限制,但社區(qū)對允許本機(jī)跨域 Ajax 請求的強(qiáng)烈抗議。許多人沒有意識(shí)到,幾乎所有瀏覽器(Internet Explorer 8+、Firefox 3.5+、Safari 4+ 和 Chrome)目前都通過稱為跨源資源共享的協(xié)議支持跨域 Ajax。
跨域資源共享 (CORS)
跨源資源共享(CORS) 是 W3C 工作草案,定義了跨源訪問源時(shí)瀏覽器和服務(wù)器必須如何通信。CORS 背后的基本思想是使用自定義 HTTP 標(biāo)頭,讓瀏覽器和服務(wù)器充分了解彼此,以確定請求或響應(yīng)應(yīng)該成功還是失敗。
對于一個(gè)簡單的請求,即使用 GET 或 POST 且不帶自定義標(biāo)頭且正文為 的請求text/plain,該請求會(huì)使用名為 的額外標(biāo)頭發(fā)送Origin。標(biāo)Origin頭包含請求頁面的來源(協(xié)議、域名和端口),以便服務(wù)器可以輕松確定是否應(yīng)該提供響應(yīng)。示例Origin標(biāo)頭可能如下所示:
Origin: https://humanwhocodes.com
如果服務(wù)器決定允許該請求,它會(huì)發(fā)送一個(gè)Access-Control-Allow-Origin標(biāo)頭,回顯與發(fā)送的相同來源或“*”(如果它是公共資源)。例如:
Access-Control-Allow-Origin: https://humanwhocodes.com
如果此標(biāo)頭丟失,或者來源不匹配,則瀏覽器將不允許該請求。如果一切順利,瀏覽器就會(huì)處理該請求。請注意,請求和響應(yīng)都不包含 cookie 信息。
前面提到的所有瀏覽器都支持這些簡單的請求。Firefox 3.5+、Safari 4+ 和 Chrome 都支持通過該XMLHttpRequest對象使用。當(dāng)嘗試打開不同來源的資源時(shí),此行為會(huì)自動(dòng)觸發(fā),無需任何額外代碼。例如:
var xhr = new XMLHttpRequest(); xhr.open("get", "https://humanwhocodes.com/some_resource/", true); xhr.onload = function(){//instead of onreadystatechange //do something }; xhr.send(null);
要在 Internet Explorer 8 中執(zhí)行相同的操作,您需要以相同的方式使用該XDomainRequest對象:
var xdr = new XDomainRequest(); xdr.open("get", " xdr.onload = function(){ //do something }; xdr.send();
Mozilla 團(tuán)隊(duì)在有關(guān) CORS 的帖子中建議您應(yīng)該檢查該withCredentials屬性是否存在,以確定瀏覽器是否通過 XHR 支持 CORS。然后,您可以結(jié)合該XDomainRequest對象的存在來覆蓋所有瀏覽器:
function createCORSRequest(method, url){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr){ xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined"){ xhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get", "https://humanwhocodes.com/"); if (request){ request.onload = function(){ //do something with request.responseText }; request.send(); }
Firefox、Safari 和 Chrome 中的對象XMLHttpRequest與 IE 對象具有足夠相似的接口XDomainRequest,因此該模式工作得相當(dāng)好。常見的接口屬性/方法有:
abort()– 用于停止已經(jīng)在進(jìn)行的請求。
onerror– 使用而不是onreadystatechange檢測錯(cuò)誤。
onload– 使用而不是onreadystatechange檢測成功。
responseText– 用于獲取響應(yīng)內(nèi)容。
send()– 用于發(fā)送請求。
預(yù)檢請求
CORS 允許通過稱為預(yù)檢請求的透明服務(wù)器驗(yàn)證機(jī)制使用自定義標(biāo)頭、GET 或 POST 以外的方法以及不同的正文內(nèi)容類型。當(dāng)您嘗試使用高級(jí)選項(xiàng)之一發(fā)出請求時(shí),系統(tǒng)會(huì)向服務(wù)器發(fā)出“預(yù)檢”請求。此請求使用 OPTIONS 方法并發(fā)送以下標(biāo)頭:
Origin– 與簡單請求相同。
Access-Control-Request-Method– 請求想要使用的方法。
Access-Control-Request-Headers– (可選)正在使用的自定義標(biāo)頭的逗號(hào)分隔列表。
假設(shè)一個(gè)帶有名為 的自定義標(biāo)頭的 POST 請求的示例NCZ:
Origin: https://humanwhocodes.com Access-Control-Request-Method: POST Access-Control-Request-Headers: NCZ
文章來源地址http://www.zghlxwxcb.cn/article/293.html
在此請求期間,服務(wù)器可以確定是否允許此類請求。服務(wù)器通過在響應(yīng)中發(fā)送以下標(biāo)頭將此信息傳達(dá)給瀏覽器:
Access-Control-Allow-Origin– 與簡單請求相同。
Access-Control-Allow-Methods– 允許的方法的逗號(hào)分隔列表。
Access-Control-Allow-Headers– 服務(wù)器允許的標(biāo)頭的逗號(hào)分隔列表。
Access-Control-Max-Age– 此預(yù)檢請求應(yīng)緩存的時(shí)間(以秒為單位)。
例子:
Access-Control-Allow-Origin: https://humanwhocodes.com Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: NCZ Access-Control-Max-Age: 1728000
一旦發(fā)出預(yù)檢請求,結(jié)果將被緩存響應(yīng)中指定的時(shí)間段;您只會(huì)在第一次發(fā)出此類請求時(shí)產(chǎn)生額外 HTTP 請求的費(fèi)用。
Firefox 3.5+、Safari 4+ 和 Chrome 均支持預(yù)檢請求;Internet Explorer 8 沒有。
憑證請求
默認(rèn)情況下,跨源請求不提供憑據(jù)(cookie、HTTP 身份驗(yàn)證和客戶端 SSL 證書)。您可以通過將該屬性設(shè)置為 true 來指定請求應(yīng)發(fā)送憑據(jù)withCredentials。如果服務(wù)器允許憑據(jù)請求,則它會(huì)使用以下 HTTP 標(biāo)頭進(jìn)行響應(yīng):
Access-Control-Allow-Credentials: true
如果發(fā)送了憑據(jù)請求并且此標(biāo)頭未作為響應(yīng)的一部分發(fā)送,則瀏覽器不會(huì)將響應(yīng)傳遞給 JavaScript(responseText是空字符串,status為 0,并且onerror()被調(diào)用)。請注意,服務(wù)器還可以發(fā)送此 HTTP 標(biāo)頭作為預(yù)檢響應(yīng)的一部分,以指示允許源發(fā)送憑證請求。
Internet Explorer 8 不支持該withCredentials屬性;Firefox 3.5、Safari 4 和 Chrome 都支持它。
結(jié)論
現(xiàn)代 Web 瀏覽器對跨域 Ajax 提供了大量可靠的支持,但大多數(shù)開發(fā)人員仍然沒有意識(shí)到這種強(qiáng)大的功能。使用時(shí)只需要一點(diǎn)額外的 JavaScript 工作和一點(diǎn)額外的服務(wù)器端工作即可確保發(fā)送正確的標(biāo)頭。IE8 的實(shí)現(xiàn)在允許高級(jí)請求和憑據(jù)請求方面落后于其他版本,但希望對 CORS 的支持將繼續(xù)改進(jìn)。文章來源:http://www.zghlxwxcb.cn/article/293.html
到此這篇關(guān)于PDF.js CORS 問題的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!