跨域的幾種方法

什么是跨域

瀏覽器出于安全方面的考慮,只允許客戶端與本域(同協(xié)議萌朱、同域名、同端口策菜,三者缺一不可)下的接口交互晶疼。不同源的客戶端腳本在沒(méi)有明確授權(quán)的情況下,不能讀寫對(duì)方的資源又憨,這被稱為同源策略翠霍。

同協(xié)議:如都是http或者h(yuǎn)ttps
同域名:如都是http://xxx.com/ahttp://xxx.com/b
同端口:如都是8080端口

而有時(shí)候,我們不得不在一個(gè)客戶端下訪問(wèn)不同域中的資源蠢莺,于是需要用到一些方法來(lái)避開瀏覽器的同源策略寒匙,這些方法被稱為跨域。
實(shí)現(xiàn)跨域有如下幾種方法:

1. JSONP

JSONP(JSON with Padding)是數(shù)據(jù)格式JSON的一種使用模式躏将,可以使網(wǎng)頁(yè)實(shí)現(xiàn)跨域請(qǐng)求锄弱。其原理主要利用了 HTMLscript標(biāo)簽。由于script是采用開放策略祸憋,通過(guò)設(shè)置src引入不同域下的資源会宪,所以可以通過(guò)script實(shí)現(xiàn)跨域,該方法需要后端支持蚯窥。jsonp跨域的實(shí)現(xiàn)步驟如下:

  • 首先客戶端定義一個(gè)數(shù)據(jù)處理函數(shù)fun掸鹅,用于處理后端服務(wù)器返回的數(shù)據(jù)喜命。
  • 創(chuàng)建一個(gè)script標(biāo)簽,并將scriptsrc設(shè)置為后端接口河劝,并在最后加一個(gè)參數(shù)callback=fun壁榕。
  • 服務(wù)端在收到由 script標(biāo)簽發(fā)出的請(qǐng)求后,會(huì)解析請(qǐng)求參數(shù)赎瞎,獲取callback對(duì)應(yīng)的fun的字符串牌里,然后將要返回的數(shù)據(jù)datafun拼接為一個(gè)'fun(data)'的字符串,返回客戶端务甥。
  • 客戶端拿到響應(yīng)后會(huì)放到script標(biāo)簽里執(zhí)行牡辽,此時(shí)會(huì)調(diào)用fun函數(shù),參數(shù)為data敞临。

下面來(lái)做個(gè)演示态辛,首先為演示方便,將系統(tǒng)的hosts做如下修改:

127.0.0.1 example.a.com
127.0.0.1 example.b.com

服務(wù)器端(用server-mock啟動(dòng)挺尿,保存圖片的url地址數(shù)據(jù)):

客戶端(展示隨機(jī)圖片):

請(qǐng)求結(jié)果:


以上例子最終實(shí)現(xiàn)了由example.a.com到example.b.com的跨域奏黑。應(yīng)注意的是,因?yàn)?code><script>只能發(fā)送GET請(qǐng)求编矾,所以jsonp只能實(shí)現(xiàn)GET請(qǐng)求的跨域熟史。如果希望能實(shí)現(xiàn)其他請(qǐng)求的跨域,就可以用接下來(lái)介紹的一種方法——CORS窄俏。

2.CORS

CORS(全稱為:Cross-Origin Resouce Sharing)跨域資源共享蹂匹,是一種通過(guò)ajax跨域請(qǐng)求資源的方法。瀏覽器將CORS請(qǐng)求分為兩大類凹蜈,簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request限寞,瀏覽器對(duì)這兩種請(qǐng)求的處理方式不一樣。如果請(qǐng)求滿足以下兩個(gè)條件仰坦,則為簡(jiǎn)單請(qǐng)求履植。

  • 請(qǐng)求方式為HEAD,GET缎岗,POST三者中第一個(gè)静尼。
  • HTTP頭部信息不超過(guò)以下幾種字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data传泊、text/plain鼠渺。

簡(jiǎn)單請(qǐng)求的實(shí)現(xiàn)方式即當(dāng)用XMLHttpRequest發(fā)請(qǐng)求時(shí),瀏覽器如果發(fā)現(xiàn)該請(qǐng)求不符合同源策略眷细,會(huì)給該請(qǐng)求加上一個(gè)請(qǐng)求頭origin拦盹,origin用來(lái)說(shuō)明本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議+域名+端口)。如果origin指定的源不在后臺(tái)允許范圍內(nèi)溪椎,后臺(tái)會(huì)返回一個(gè)正常的HTTP響應(yīng)普舆,然后瀏覽器會(huì)發(fā)現(xiàn)該響應(yīng)頭部信息不包含Access-Control-Allow-Origin字段恬口,然后拋出一個(gè)錯(cuò)誤,該錯(cuò)誤被XMLHttpRequest的onerror函數(shù)捕獲沼侣,響應(yīng)被駁回祖能,但因?yàn)樵撳e(cuò)誤無(wú)法通過(guò)狀態(tài)碼識(shí)別,所以HTTP回應(yīng)的狀態(tài)碼還是200蛾洛。如果origin在后臺(tái)允許范圍內(nèi)养铸,則服務(wù)器返回的響應(yīng),會(huì)包含Access-Control-Allow-Origin:Origin(指定的源)信息轧膘,瀏覽器此時(shí)不會(huì)拋錯(cuò)钞螟,響應(yīng)能正常處理。
非簡(jiǎn)單請(qǐng)求是是請(qǐng)求方法為PUT或DELETE谎碍,又或者Content-Type為application/json的對(duì)服務(wù)器有特殊要求的請(qǐng)求鳞滨。非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信前增加一次HTTP查詢蟆淀,稱為預(yù)檢(preflight)拯啦,詢問(wèn)服務(wù)器當(dāng)前網(wǎng)頁(yè)所在域名是否在服務(wù)器的許可名單中,如果在扳碍,則發(fā)出正式的XMLHttpRequest提岔,之后就與簡(jiǎn)單請(qǐng)求一樣,不在則報(bào)錯(cuò)笋敞。
依舊用上面的例子。

服務(wù)器端(設(shè)置一個(gè)響應(yīng)頭荠瘪,里面包含了允許請(qǐng)求的域名信息)

客戶端(用ajax發(fā)請(qǐng)求)

最終實(shí)現(xiàn)的效果與第一個(gè)jsonp的例子一樣夯巷。

3.降域

還有一種方式,就是通過(guò)降域來(lái)實(shí)現(xiàn)跨域哀墓。即通過(guò)設(shè)置document.domain的方式趁餐,將兩個(gè)域名的domain設(shè)置為一個(gè),如對(duì)于a.example.com和b.example.com篮绰,可以通過(guò)js設(shè)置document.domain = "example.com"后雷,實(shí)現(xiàn)跨域。
做個(gè)演示吠各,假設(shè)在http://a.example.com:8080下有一個(gè)a.html文件臀突,其中a.html中有一個(gè)iframe,它的srchttp://b.example.com:8080/b.html贾漏。



正常情況下候学,由于a.html,b.html不同源纵散,他們之間無(wú)法正常通信梳码,但在設(shè)置document.domain = "example.com"后隐圾,兩邊可以互相通信。
最終效果如下:

用降域方法實(shí)現(xiàn)跨域操作簡(jiǎn)單掰茶,但是有一些缺點(diǎn)暇藏。比如域名只能往下設(shè)置,不能回去濒蒋,比如從example.com回到a.example.com盐碱。同時(shí)如果一個(gè)子域名被攻擊,多個(gè)被降域的域名都會(huì)被連帶攻擊啊胶,有很大的安全風(fēng)險(xiǎn)甸各。

4.postMessage

postMessage是一個(gè)web API,可以實(shí)現(xiàn)跨域通信焰坪。window.postMessage()被調(diào)用時(shí)趣倾,會(huì)在所有頁(yè)面腳本執(zhí)行完畢后,向目標(biāo)窗口派發(fā)一個(gè)MessageEvent消息某饰。語(yǔ)法如下:

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • otherWindow表示目標(biāo)窗口的一個(gè)引用儒恋,比如iframecontentWindow屬性、執(zhí)行window.open返回的窗口對(duì)象黔漂、或者是命名過(guò)或通過(guò)數(shù)值索引的window.frames诫尽。
  • message表示需要發(fā)送到目標(biāo)窗口的數(shù)據(jù)。
  • targetOrigin決定了哪些窗口可以接收消息炬守,其值可以是字符串"*"(表示無(wú)限制)或者一個(gè)URI牧嫉。
  • transfer是一串和message同時(shí)傳遞的Transferable 對(duì)象,這些對(duì)象的所有權(quán)將被轉(zhuǎn)移給消息的接收方减途,而發(fā)送一方將不再保有所有權(quán)酣藻。

MessageEvent具有如下屬性:

  • message屬性表示該message的類型。
  • data屬性為window.postMessage的第一個(gè)參數(shù)鳍置;
  • origin 屬性表示調(diào)用window.postMessage()方法時(shí)調(diào)用頁(yè)面的當(dāng)前狀態(tài)辽剧;
  • source 屬性記錄調(diào)用window.postMessage()方法的窗口信息。

用一個(gè)與上面降域類似的例子來(lái)做演示税产。同樣有兩個(gè)頁(yè)面a.html和b.html怕轿,a.html中的iframesrc指向b.html。


最終實(shí)現(xiàn)a.html與b.html通信效果如下:

使用postMessage方法應(yīng)注意的是辟拷,如果不希望從其他網(wǎng)站接收message撞羽,那么不要為message事件添加任何監(jiān)聽(tīng)器。如果確實(shí)希望接收其他網(wǎng)站的message梧兼,那么應(yīng)該始終使用origin和source屬性來(lái)驗(yàn)證發(fā)件人的身份放吩,以免被惡意的網(wǎng)站攻擊。

小結(jié)

以上就是幾種常見(jiàn)的跨域方法羽杰,各有優(yōu)劣渡紫,且各自都有一定的安全問(wèn)題到推,在日常應(yīng)用中,需要有針對(duì)性的使用惕澎,對(duì)可能的安全風(fēng)險(xiǎn)采取相應(yīng)措施莉测。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市唧喉,隨后出現(xiàn)的幾起案子捣卤,更是在濱河造成了極大的恐慌,老刑警劉巖八孝,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件董朝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡干跛,警方通過(guò)查閱死者的電腦和手機(jī)子姜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)楼入,“玉大人哥捕,你說(shuō)我怎么就攤上這事〖涡埽” “怎么了遥赚?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)阐肤。 經(jīng)常有香客問(wèn)我凫佛,道長(zhǎng),這世上最難降的妖魔是什么孕惜? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任御蒲,我火速辦了婚禮,結(jié)果婚禮上诊赊,老公的妹妹穿的比我還像新娘。我一直安慰自己府瞄,他們只是感情好碧磅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遵馆,像睡著了一般鲸郊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上货邓,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天秆撮,我揣著相機(jī)與錄音,去河邊找鬼换况。 笑死职辨,一個(gè)胖子當(dāng)著我的面吹牛盗蟆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舒裤,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼喳资,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了腾供?” 一聲冷哼從身側(cè)響起仆邓,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伴鳖,沒(méi)想到半個(gè)月后节值,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榜聂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年搞疗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峻汉。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贴汪,死狀恐怖籍琳,靈堂內(nèi)的尸體忽然破棺而出鼠次,到底是詐尸還是另有隱情械哟,我是刑警寧澤惨恭,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布女轿,位于F島的核電站原献,受9級(jí)特大地震影響坎背,放射性物質(zhì)發(fā)生泄漏展东。R本人自食惡果不足惜柜思,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一岩调、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赡盘,春花似錦号枕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至抛姑,卻和暖如春赞厕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背定硝。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工皿桑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓诲侮,卻偏偏與公主長(zhǎng)得像镀虐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浆西,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • CORS 實(shí)現(xiàn)CORS需要瀏覽器和服務(wù)器的共同協(xié)作粉私。對(duì)于前端開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX在代碼方面沒(méi)有...
    饑人谷_有點(diǎn)熱閱讀 1,281評(píng)論 0 2
  • 什么是跨域 說(shuō)到跨域必須先解釋什么是同源策略近零,它是由Netscape提出的一個(gè)著名的安全策略诺核。瀏覽器出于安全方面的...
    8d2855a6c5d0閱讀 1,337評(píng)論 0 0
  • 概念:只要協(xié)議、域名久信、端口有任何一個(gè)不同窖杀,都被當(dāng)作是不同的域。 所有具有 src 屬性的HTML標(biāo)簽都可以跨域 原...
    jeffAAA閱讀 2,516評(píng)論 0 0
  • 同源策略 瀏覽器出于安全方面的考慮裙士,為了保證用戶信息的安全入客,防止惡意的網(wǎng)站竊取數(shù)據(jù)。只允許與本域下的接口交互腿椎。不同...
    祝余_scrapy閱讀 403評(píng)論 0 0
  • 1. AJAX AJAX(Asynchronous JavaScript and XML)桌硫,意思就是用JavaSc...
    公子七閱讀 5,005評(píng)論 0 5