摘要:首先糾正一個(gè)誤區(qū),跨域并非瀏覽器限制了發(fā)起跨站請求的這種能力,恰恰相反,我們可以發(fā)出請求,服務(wù)端也可以接收到請求并正常返回?cái)?shù)據(jù),只不過在返回之后瀏覽器會阻止非同源數(shù)據(jù),從而在控制臺打出一系列報(bào)錯(cuò)信息。
兼容性查找首先糾正一個(gè)誤區(qū),跨域并非瀏覽器限制了發(fā)起跨站請求的這種能力,恰恰相反,我們可以發(fā)出請求,服務(wù)端也可以接收到請求并正常返回?cái)?shù)據(jù),只不過在返回之后瀏覽器會阻止非同源數(shù)據(jù)(response),從而在控制臺打出一系列報(bào)錯(cuò)信息。
原文地址:說說跨域那些事兒,遷移到簡書上來和大家共享
文章中會涉及一系列兼容性的圖解(mdn & can i use)和一些專有名詞(mdn),可以通過兩個(gè)渠道來查看
Can I Use
MDN
跨域類型定義就不說了,從字面也可以看其含義,首先我們認(rèn)識下哪些情況屬于跨域,可以分為以下幾點(diǎn):
協(xié)議不同,如http, https;
端口不同;
主域相同,子域不同;
主域不同;
ip地址和域名之間也算是跨域,瀏覽器不會自動(dòng)做ip域名的映射;
解決方案document.domain
window.name
jsonp
postMessage
cors
document.domain
關(guān)鍵點(diǎn)
跨域分為兩種,一種xhr不能訪問不同源的文檔,另一種是不同window之間不能進(jìn)行交互操作;
document.domain主要是解決第二種情況,且只能適用于主域相同子域不同的情況;
document.domain的設(shè)置是有限制的,我們只能把document.domain設(shè)置成自身或更高一級的父域,且主域必須相同。例如:a.b.example.com中某個(gè)文檔的document.domain可以設(shè)成a.b.example.com、b.example.com 、example.com中的任意一個(gè),但是不可以設(shè)成c.a.b.example.com,因?yàn)檫@是當(dāng)前域的子域,也不可以設(shè)成baidu.com,因?yàn)橹饔蛞呀?jīng)不相同了。
兼容性:所有瀏覽器都支持;
優(yōu)點(diǎn):
可以實(shí)現(xiàn)不同window之間的相互訪問和操作;
缺點(diǎn):
只適用于父子window之間的通信,不能用于xhr;
只能在主域相同且子域不同的情況下使用;
使用方式
a(當(dāng)前頁面或父頁面)頁面中加入document.domain = "example.com";
b(當(dāng)前頁面或子頁面)頁面中加入document.domain = "example.com";
a頁面訪問b頁面里面的數(shù)據(jù)或者方法;
window.name關(guān)鍵點(diǎn):window.name在頁面的生命周期里共享一個(gè)window.name;
兼容性:所有瀏覽器都支持;
優(yōu)點(diǎn):
最簡單的利用了瀏覽器的特性來做到不同域之間的數(shù)據(jù)傳遞;
不需要前端和后端的特殊配制;
缺點(diǎn):
大小限制:window.name最大size是2M左右,不同瀏覽器中會有不同約定;
安全性:當(dāng)前頁面所有window都可以修改,很不安全;
數(shù)據(jù)類型:傳遞數(shù)據(jù)只能限于字符串,如果是對象或者其他會自動(dòng)被轉(zhuǎn)化為字符串,如下;
使用方式:修改window.name的值即可;
jsonp關(guān)鍵點(diǎn):瀏覽器對XHR做了同源策略,但并沒有將這種方式延續(xù)到script上(其實(shí)還有iframe,img等),從而可以利用動(dòng)態(tài)script標(biāo)簽技術(shù)來做到跨域請求的作用。至于為什么會這樣設(shè)計(jì),本人也不太清楚,有可能是歷史遺跡(漏洞),有可能是某些方面的技術(shù)瓶頸,也有可能是為了滿足某些需求專門定制的,總之這項(xiàng)技術(shù)方案我們過去可以用,現(xiàn)在可以用就ok,至于將來應(yīng)該也是會存在的,畢竟現(xiàn)在已經(jīng)應(yīng)用在很多家站點(diǎn)上,就算會廢棄,也會有一段時(shí)間迭代。
兼容性:所有瀏覽器都兼容這種方式;
優(yōu)點(diǎn):很明顯前端可以很輕松的做到跨域請求;
缺點(diǎn)
只能通過GET方式請求,一方面是參數(shù)長度有限制,二是安全性比較差;
后端需要知道前端的cb是什么樣的結(jié)構(gòu),主要在參數(shù)和回調(diào)名;
后端需要進(jìn)行參數(shù)和cb的拼接然后才能執(zhí)行;
使用方式
/** 前端生成script標(biāo)簽,并將src中傳入需要執(zhí)行的callback **/ /** 后端接到參數(shù)后給callback加入?yún)?shù)并執(zhí)行 **/postMessage
關(guān)鍵點(diǎn):postMessage是h5引入的一個(gè)新概念,現(xiàn)在也在進(jìn)一步的推廣和發(fā)展中,他進(jìn)行了一系列的封裝,我們可以通過window.postMessage的方式進(jìn)行使用,并可以監(jiān)聽其發(fā)送的消息;
兼容性:下圖是postMessage的兼容圖,移動(dòng)端可以放心用,但是pc端需要做降級處理,具體可以根據(jù)文中介紹的這幾種跨域方式來則情選擇;
優(yōu)點(diǎn)
不需要后端介入就可以非常簡單的的做到跨域,一個(gè)函數(shù)外加兩個(gè)參數(shù)(請求url,發(fā)送數(shù)據(jù))就可以搞定;
移動(dòng)端兼容性好;
缺點(diǎn)
無法做到一對一的傳遞方式:監(jiān)聽中需要做很多消息的識別,由于postMessage發(fā)出的消息對于同一個(gè)頁面的不同功能相當(dāng)于一個(gè)廣播的過程,該頁面的所有onmessage都會收到,所以需要做消息的判斷;
安全性問題:三方可以通過截獲,注入html或者腳本的形式監(jiān)聽到消息,從而能夠做到篡改的效果,所以在postMessage和onmessage中一定要做好這方面的限制;
發(fā)送的數(shù)據(jù)會通過結(jié)構(gòu)化克隆算法進(jìn)行序列化,所以只有滿足該算法要求的參數(shù)才能夠被解析,否則會報(bào)錯(cuò),如function就不能當(dāng)作參數(shù)進(jìn)行傳遞;
使用方式:下面是前段時(shí)間寫的一個(gè)通信的函數(shù),sendMessage_負(fù)責(zé)發(fā)送消息,bindEvent_負(fù)責(zé)消息的監(jiān)聽并處理,可以通過代碼來做一個(gè)大致了解;
Storage.prototype.sendMessage_ = function(type, params, fn) { if (this.topWindow) { this.handleCookie_(type, params, fn); return; } var eventId = this.addToQueue_(fn, type); var storageIframe = document.getElementById("mip-storage-iframe"); var element = document.createElement("a"); element.href = this.origin; var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1); storageIframe.contentWindow.postMessage({ type: type, params: params, eventId: eventId }, origin); } Storage.prototype.bindEvent_ = function() { window.onmessage = function (res) { // 判斷消息來源 if (window == res.source.window.parent && res.data.type === this.messageType.RES && window.location.href.match(res.origin.host).length > 0) { var fn = this.eventQueue[res.data.eventId]; fn && fn(); delete this.eventQueue[res.data.eventId]; // reset id var isEmpty = true; for (var t in this.eventQueue) { isEmpty = false; } if (isEmpty) { this.id = 0; } } }.bind(this); }cors
關(guān)鍵點(diǎn):cors是一種通過前后端http header配置來進(jìn)行跨域的一種方式;
兼容性:如果不考慮pc端的IE,移動(dòng)端的opera的話那兼容性還是不錯(cuò)的,針對ie和opera可以做適當(dāng)?shù)慕导壧幚恚?br>
安全策略
請求
origin:通過http頭中的origin判斷域名是否是允許的;
Example-Same-origin:如果http origin不存在,最好能夠自己在請求頭中加入該參數(shù)來標(biāo)示是否是同源,true表示請求來自于同域名下(同域名下請求不帶origin);如果該字段存在并且為true則允許請求接口,否則禁止;
Example_source_origin:該參數(shù)同origin,是在origin不存在的情況下用來標(biāo)示請求來源的url;
返回
Access-Control-Allow-Origin: origin,origin表示允許哪些網(wǎng)站請求,不建議設(shè)置為*;
Access-Control-Expose-Headers:Example-Access-Control-Allow-Source-Origin,允許http返回中包含該字段,可以通過這種方式在返回頭中加入自定義字段,如該例子中的Example-Access-Control-Allow-Source-Origin;
優(yōu)點(diǎn)
前端方便不少,只需要發(fā)請求而不用考慮跨域問題;
安全性能夠得以控制和保障;
缺點(diǎn)
兼容性不全面,需要做降級處理;
使用方式
正常請求即可,無論是你要用xhr,還是用一些封裝好的組件,如fetch,fetchJsonp,亦或是jquery一類的技術(shù)均可;
后端在response時(shí)需要設(shè)置一定的配置參數(shù),并保證安全策略,具體方案可以參照下面安全策略模塊;
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86738.html
摘要:雖然今年沒有換工作的打算但為了跟上時(shí)代的腳步還是忍不住整理了一份最新前端知識點(diǎn)知識點(diǎn)匯總新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪異模式和的區(qū)別使用的好處標(biāo)簽廢棄的標(biāo)簽,和一些定位寫法放置位置和原因什么是漸進(jìn)式渲染模板語言原理盒模型,新特性,偽 雖然今年沒有換工作的打算 但為了跟上時(shí)代的腳步 還是忍不住整理了一份最新前端知識點(diǎn) 知識點(diǎn)匯總1.HTMLHTML5新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪...
摘要:雖然今年沒有換工作的打算但為了跟上時(shí)代的腳步還是忍不住整理了一份最新前端知識點(diǎn)知識點(diǎn)匯總新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪異模式和的區(qū)別使用的好處標(biāo)簽廢棄的標(biāo)簽,和一些定位寫法放置位置和原因什么是漸進(jìn)式渲染模板語言原理盒模型,新特性,偽 雖然今年沒有換工作的打算 但為了跟上時(shí)代的腳步 還是忍不住整理了一份最新前端知識點(diǎn) 知識點(diǎn)匯總1.HTMLHTML5新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪...
摘要:最近微信低調(diào)發(fā)布了新版本。之所以說這是一個(gè)重大更新,是因?yàn)樯洗挝⑿诺陌姹咎栍缮壍揭呀?jīng)是年的事情了實(shí)際的更新也是挺大的,第一感受就是風(fēng)格更加扁平化了。如果你能用上微信的版,那一定不簡單。 最近微信低調(diào)發(fā)布了 iOS 新版本: 7.0 。之所以說這是一個(gè)重大更新,是因?yàn)樯洗挝⑿诺陌姹咎栍?5.x 升級到 6.0 已經(jīng)是 2014 年 的事情了! 實(shí)際的更新也是挺大的,第一感受就是 UI ...
閱讀 1049·2021-11-22 13:53
閱讀 1599·2021-11-17 09:33
閱讀 2401·2021-10-14 09:43
閱讀 2863·2021-09-01 11:41
閱讀 2280·2021-09-01 10:44
閱讀 2920·2021-08-31 09:39
閱讀 1457·2019-08-30 15:44
閱讀 1866·2019-08-30 13:02