摘要:但是如果是一級(jí)域名相同,二級(jí)及以上域名不同的網(wǎng)頁(yè)可以通過(guò)設(shè)置來(lái)共享。設(shè)置有兩種方式前端腳本中設(shè)置服務(wù)器接口設(shè)置時(shí)指定所屬的域名為一級(jí)域名。服務(wù)器檢查過(guò)預(yù)檢請(qǐng)求頭之后,確認(rèn)允許跨域請(qǐng)求,就可以做出回應(yīng)。
一、跨域問(wèn)題產(chǎn)生的原因
根本原因是由于瀏覽器的“同源政策”。
同源政策由網(wǎng)景公司(Netscape)1995年引入瀏覽器。目前所有瀏覽器都實(shí)行這個(gè)政策。
所謂同源是指“三個(gè)相同”:
協(xié)議相同
域名相同
端口相同
目前,如果非同源,共有三種行為收到限制。
Cookie、LocalStorage 和 IndexDB 無(wú)法讀取。
DOM無(wú)法獲取
AJAX請(qǐng)求不能發(fā)送
二、跨域問(wèn)題處理Cookie是服務(wù)器寫入瀏覽器的信息,只有同源的網(wǎng)頁(yè)才能共享。但是如果是一級(jí)域名相同,二級(jí)(及以上)域名不同的網(wǎng)頁(yè)可以通過(guò)設(shè)置document.domain來(lái)共享cookie。
比如,w1.example.com 和 w2.example.com是不同源的,w1.example.com/index.html (A網(wǎng)頁(yè)) 和 w2.example.com/index.html (B網(wǎng)頁(yè))只要設(shè)置相同的document.domain就可以共享Cookie。
設(shè)置domain有兩種方式:1.前端js腳本中設(shè)置 2.服務(wù)器接口設(shè)置cookie時(shí)指定Cookie所屬的域名為一級(jí)域名。
在A網(wǎng)頁(yè)設(shè)置
document.domain = “example.com”; document.cookie = “userName = aaa”;
這樣在B網(wǎng)頁(yè)就可以讀到這個(gè)Cookie
var cookie = document.cookie; // userName = aaa;
Set-Cookie: userName = aaa ; domain = .example.com ; path = /
如果兩個(gè)網(wǎng)頁(yè)不同源,就無(wú)法拿到對(duì)方的DOM。典型例子是iframe和window.open方法打開(kāi)的窗口,它們與父窗口無(wú)法通信。
如果兩個(gè)窗口只是二級(jí)域名不同,一級(jí)域名相同的話,那么設(shè)置document.domain屬性,就可以規(guī)避同源政策。拿到DOM。對(duì)于完全不同源的網(wǎng)站,目前有三種方法可以解決跨域窗口通信問(wèn)題:
片段標(biāo)識(shí)符
window.name
跨文檔通信API
片段標(biāo)識(shí)符指的是URL的#后面的部分,如http://example.com/index.html...。如果只是改變片段標(biāo)識(shí)符部分,頁(yè)面不會(huì)刷新。
父窗口可以把信息寫入子窗口的片段標(biāo)識(shí)符中,
var src = originURL + ‘#’ + data; document.getElementById(‘#iframe’).src = src;
子窗口通過(guò)監(jiān)聽(tīng)hashchange事件得到通知
window.onhashchange = checkMessage; function checkMessage(){ var message = window.location.hash; //... }
同樣子窗口也可以修改父窗口的片段標(biāo)識(shí)符。
parent.location.href = target + ‘#" + hash;
瀏覽器窗口有window.name屬性。這個(gè)屬性最大的特點(diǎn)是,無(wú)論是否同源,只要在同一個(gè)窗口里,前一個(gè)網(wǎng)頁(yè)設(shè)置了這個(gè)屬性,后一個(gè)網(wǎng)頁(yè)就可以讀取它。
postMessage是HTML5引入的一個(gè)全新的API:跨文檔通信API提供的一個(gè)全局方法,允許跨窗口通信,不論是否同源。
父窗口發(fā)送message
var popup = window.open(‘http://aaa.com’,"title"); popup.postMessage(‘Hello World’, ‘http://aaa.com");
子窗口監(jiān)聽(tīng)message事件
window.addeventlistener(‘message’,function( e ){ console.log( e.data ); });
message事件的event對(duì)象提供三個(gè)屬性
event.source 發(fā)送消息的窗口
event.origin 消息發(fā)向的網(wǎng)址
event.data 消息內(nèi)容
用window.postMessage可解決。
同源政策規(guī)定,AJAX只能發(fā)給同源的網(wǎng)址,否則會(huì)報(bào)錯(cuò)。除了用服務(wù)器代理的方法(nginx反向代理等),有以下方法可以解決。
原理是利用script標(biāo)簽的src屬性,接受JSON數(shù)據(jù)。關(guān)鍵在于規(guī)定一個(gè)callback方法名,在url中以參數(shù)形式傳給服務(wù)器,由服務(wù)器將數(shù)據(jù)以參數(shù)形式注入callback中,供js腳本使用。
缺點(diǎn)是只能發(fā)送get請(qǐng)求,優(yōu)點(diǎn)是支持老式瀏覽器。
CORS即跨源資源分享,是W3C標(biāo)準(zhǔn),是跨源AJAX請(qǐng)求的根本解決方法。相比JSONP,CORS允許任何類型的請(qǐng)求。
目前除了IE之外的所有瀏覽器都支持CORS,IE不能低于IE10版本。
瀏覽器將CORS請(qǐng)求分為兩類,簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。
簡(jiǎn)單請(qǐng)求條件:
1. 請(qǐng)求方法 GET、POST、HEAD; 2. http頭信息不超過(guò) Accept 、Accept-Language 、Content-Language、Last-Event-ID; 3. content-type只限于三個(gè)值: application/x-www-form-urlencoded、multipart/form-data、text/plain
對(duì)于簡(jiǎn)單請(qǐng)求,瀏覽器的處理是直接發(fā)出CORS請(qǐng)求,也就是在頭信息中增加一個(gè)字段Origin,該字段說(shuō)明本次請(qǐng)求是來(lái)自哪個(gè)源(協(xié)議+域名+端口)。服務(wù)器根據(jù)這個(gè)值,判斷是否同意此次請(qǐng)求。
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的相應(yīng),會(huì)多幾個(gè)頭信息字段。
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
Access-Control-Allow-Origin:該字段必須,它的值要么是請(qǐng)求是Origin的值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。
Access-Control-Allow-Credentials:該字段可選。值是一個(gè)布爾值,表示是否允許發(fā)送Cookie,默認(rèn)為true,表示可以發(fā)送。
Access-Control-Expose-Headers:該字段可選。CORS請(qǐng)求是XHR對(duì)象的getResponseHeader( ) 方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language、Content-Type、Expire、Last-Modified、Pragma。如果想要拿到其他字段,就要在Access-Control-Expose-Headers中指定。
注意,如果要將Cookie發(fā)送到服務(wù)器,除了服務(wù)器要設(shè)置Access-Control-Allow-Credentials字段以外,瀏覽器在發(fā)送AJAX請(qǐng)求是也要保證xhr.withCredentials屬性為true,否則瀏覽器既不會(huì)向服務(wù)器發(fā)送cookie,服務(wù)器設(shè)置cookie的操作也不會(huì)成功。但是默認(rèn)情況下,該屬性是為true的。
另外需要注意的是,如果要操作Cookie,Access-Control-Allow-Origin就不能設(shè)置為*,必須明確是哪個(gè)網(wǎng)址過(guò)來(lái)的請(qǐng)求。
對(duì)于非簡(jiǎn)單請(qǐng)求:
非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP請(qǐng)求,成為“預(yù)檢”請(qǐng)求。
瀏覽器先詢問(wèn)服務(wù)器,當(dāng)前網(wǎng)頁(yè)所在域名是否在服務(wù)器的許可名單中,以及可以使用哪些HTTP動(dòng)詞和頭信息字段。只有得到肯定答復(fù),瀏覽器才會(huì)發(fā)出正式的XMLHttpRequest請(qǐng)求,否則報(bào)錯(cuò)。
預(yù)檢請(qǐng)求的方法是OPTIONS,頭信息中的關(guān)鍵字是Origin,標(biāo)識(shí)請(qǐng)求來(lái)自哪個(gè)源。另外還包含兩個(gè)特殊字段:
Access-Control-Request-Method:該字段是必須的,用于流出瀏覽器的CORS請(qǐng)求會(huì)用到那些HTTP方法。
Access-Control-Request-Headers:該字段用來(lái)指定CORS會(huì)額外發(fā)出的頭信息字段。
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
服務(wù)器檢查過(guò)預(yù)檢請(qǐng)求頭之后,確認(rèn)允許跨域請(qǐng)求,就可以做出回應(yīng)。
響應(yīng)頭部信息的關(guān)鍵字段是Access-Control-Allow-Origin,為*或者一個(gè)完整域名,表示允許的請(qǐng)求來(lái)源。
如果服務(wù)器否定了“預(yù)檢”請(qǐng)求,會(huì)返回一個(gè)正常的HTTP回應(yīng),不包含任何CORS相關(guān)的字段。這是瀏覽器會(huì)認(rèn)定,服務(wù)器不同意預(yù)檢請(qǐng)求,因此會(huì)觸發(fā)一個(gè)錯(cuò)誤,唄XHR對(duì)象的onerror函數(shù)捕獲。并在控制臺(tái)打印。
成功的話還有幾個(gè)與CORS相關(guān)的響應(yīng)頭字段:
Access-Control-Allow-Methods:必須。表示服務(wù)器支持的跨域請(qǐng)求方法。注意會(huì)返回所有支持的方法,以此避免多次預(yù)檢請(qǐng)求。
Access-Control-Allow-Headers:如果請(qǐng)求頭包含該字段,則服務(wù)器響應(yīng)也是必須的。
Access-Control-Allow-Credentials:是否支持cookie傳輸
Access-Control-Max-Age:可選。用來(lái)指定本次預(yù)檢請(qǐng)求的有效期,單位為秒。在此期間不用發(fā)出另一條預(yù)檢請(qǐng)求。
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
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
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
一旦服務(wù)器通過(guò)了預(yù)檢請(qǐng)求,以后每次瀏覽器正常的CORS請(qǐng)求,就和簡(jiǎn)單請(qǐng)求一樣,會(huì)有一個(gè)Origin字段,服務(wù)器回應(yīng)也會(huì)有一個(gè)Access-Control-Allow-origin頭信息字段。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/90154.html
摘要:跨域的產(chǎn)生不用多講,作為一名前端開(kāi)發(fā)人員,相信大家都知道跨域是因?yàn)闉g覽器的同源策略所導(dǎo)致的。瀏覽器引入同源策略主要是為了防止,攻擊。其指明了實(shí)際請(qǐng)求所允許使用的方法。 跨域,相信大家無(wú)論是在工作中還是在面試中經(jīng)常遇到這個(gè)問(wèn)題,常常在網(wǎng)上看到別人所整理的一些方法,看似知道是怎么回事,但如果沒(méi)有動(dòng)手實(shí)踐過(guò),總覺(jué)得自己沒(méi)有真正的掌握,在這里,通過(guò)自己認(rèn)真思考整理一些常用的方法。 跨域的產(chǎn)生 ...
摘要:跨域的產(chǎn)生不用多講,作為一名前端開(kāi)發(fā)人員,相信大家都知道跨域是因?yàn)闉g覽器的同源策略所導(dǎo)致的。瀏覽器引入同源策略主要是為了防止,攻擊。其指明了實(shí)際請(qǐng)求所允許使用的方法。 跨域,相信大家無(wú)論是在工作中還是在面試中經(jīng)常遇到這個(gè)問(wèn)題,常常在網(wǎng)上看到別人所整理的一些方法,看似知道是怎么回事,但如果沒(méi)有動(dòng)手實(shí)踐過(guò),總覺(jué)得自己沒(méi)有真正的掌握,在這里,通過(guò)自己認(rèn)真思考整理一些常用的方法。 跨域的產(chǎn)生 ...
摘要:跨域的產(chǎn)生不用多講,作為一名前端開(kāi)發(fā)人員,相信大家都知道跨域是因?yàn)闉g覽器的同源策略所導(dǎo)致的。瀏覽器引入同源策略主要是為了防止,攻擊。其指明了實(shí)際請(qǐng)求所允許使用的方法。 跨域,相信大家無(wú)論是在工作中還是在面試中經(jīng)常遇到這個(gè)問(wèn)題,常常在網(wǎng)上看到別人所整理的一些方法,看似知道是怎么回事,但如果沒(méi)有動(dòng)手實(shí)踐過(guò),總覺(jué)得自己沒(méi)有真正的掌握,在這里,通過(guò)自己認(rèn)真思考整理一些常用的方法。 跨域的產(chǎn)生 ...
摘要:因?yàn)橥床呗缘南拗疲覀儾荒茉谂c外部服務(wù)器進(jìn)行通信的時(shí)候使用。這個(gè)是跨域服務(wù)器取數(shù)據(jù)的接口,參數(shù)為回調(diào)函數(shù)的名字,返回的格式為原理首先在客戶端注冊(cè)一個(gè)然后把的名字傳給服務(wù)器。 一、同源策略 同源策略,它是由Netscape提出的一個(gè)著名的安全策略,現(xiàn)在所有的可支持javascript的瀏覽器都會(huì)使用這個(gè)策略。 為什么需要同源策略,這里舉個(gè)例子: 假設(shè)現(xiàn)在沒(méi)有同源策略,會(huì)發(fā)生什么事...
摘要:同源策略做了很嚴(yán)格的限制,但是在實(shí)際的場(chǎng)景中,又確實(shí)有很多地方需要突破同源策略的限制,也就是我們常說(shuō)的跨域。使用跨域由于同源策略,一般來(lái)說(shuō)位于的網(wǎng)頁(yè)無(wú)法與不是的服務(wù)器溝通,而的元素是一個(gè)例外。 本菜雞最近在寫某個(gè)頁(yè)面請(qǐng)求數(shù)據(jù)時(shí),報(bào)了如下的錯(cuò)誤。 Failed to load https://...:No Access-Control-Allow-Origin header is pre...
閱讀 2187·2021-11-18 10:02
閱讀 3289·2021-11-11 16:55
閱讀 2694·2021-09-14 18:02
閱讀 2426·2021-09-04 16:41
閱讀 2056·2021-09-04 16:40
閱讀 1165·2019-08-30 15:56
閱讀 2213·2019-08-30 15:54
閱讀 3161·2019-08-30 14:15