摘要:數(shù)據(jù)仍然是通過(guò)頁(yè)面獲得,頁(yè)面僅需向頁(yè)面?zhèn)鬟f即可,頁(yè)面拿到函數(shù)名,并通過(guò)傳遞從服務(wù)器拿到的數(shù)據(jù),在頁(yè)面執(zhí)行頁(yè)面的回調(diào)函數(shù),回調(diào)函數(shù)執(zhí)行完畢后移除頁(yè)面以及該函數(shù)。以上是我所知道的解決跨域請(qǐng)求的兩種方法。
iframe跨域的基本前提是,一個(gè)頁(yè)面可以嵌套非同源站點(diǎn)的html文件,以及某一個(gè)域名下的html頁(yè)面可以通過(guò)腳本向同域名服務(wù)器發(fā)出ajax請(qǐng)求。當(dāng)一個(gè)域名為domain1下的頁(yè)面A想要向domain2發(fā)出ajax請(qǐng)求時(shí),由于同源策略的限制無(wú)法直接請(qǐng)求到數(shù)據(jù),但是可以在頁(yè)面A中動(dòng)態(tài)添加一個(gè)display設(shè)置為none的iframe,該iframe的src為domain2下的html頁(yè)面B,由頁(yè)面B來(lái)發(fā)出ajax請(qǐng)求,因?yàn)轫?yè)面B是domain2下的所以可以成功發(fā)出請(qǐng)求。當(dāng)B頁(yè)面拿到數(shù)據(jù)之后再傳遞給A頁(yè)面。
可以利用HTML5的postMessage來(lái)向A頁(yè)面?zhèn)鬟f數(shù)據(jù)。
將通過(guò)一個(gè)demo來(lái)具體說(shuō)明如何操作,該demo涉及到兩個(gè)域名 http://localhost:3000 以及 http://127.0.0.1:3001。向 http://localhost:3000/a.html中嵌入 http://127.0.0.1:3001/b.html頁(yè)面,在 http://127.0.0.1:3001/b.html發(fā)出本域名下的ajax請(qǐng)求。
先舉一個(gè)簡(jiǎn)單的例子。
a.html:
Title
b.html:
Title
a頁(yè)面中直接嵌入b頁(yè)面,b頁(yè)面加載后執(zhí)行腳本,向同源服務(wù)器發(fā)出請(qǐng)求,拿到數(shù)據(jù)后發(fā)送給a頁(yè)面。
這里強(qiáng)調(diào)一下:
1.代碼中寫(xiě)的是window.parent而非window
2.代碼中的第二個(gè)參數(shù)寫(xiě)為"*",也可以指定精確的目標(biāo)origin
當(dāng)然實(shí)際開(kāi)發(fā)中一個(gè)頁(yè)面要發(fā)出很多個(gè)請(qǐng)求,并且根據(jù)用戶操作不同可能要發(fā)出不一樣的請(qǐng)求,所以需要進(jìn)一步的封裝。
a頁(yè)面通過(guò)b頁(yè)面發(fā)出請(qǐng)求,這需要將發(fā)送請(qǐng)求的url以及請(qǐng)求的類型和請(qǐng)求參數(shù)等信息傳遞到b頁(yè)面,可以直接通過(guò)嵌入的iframe的src來(lái)傳遞,然后b頁(yè)面根據(jù)location.search的值來(lái)獲取以上的信息。
我們的目標(biāo)是構(gòu)建一個(gè)形如iframeAjax(params,cb)的函數(shù)。
其中params中,包括了b頁(yè)面的url,ajax請(qǐng)求的最終目標(biāo)url,ajax請(qǐng)求的種類,以及ajax請(qǐng)求的參數(shù)。
格式如下:
let {targetUrl, queryUrl, type, data = {}} = params
剛才已經(jīng)提到過(guò),a頁(yè)面通過(guò)設(shè)置iframe的src來(lái)向b頁(yè)面?zhèn)鬟f各種參數(shù)。
我們將type以及queryUrl合并到data中:
Object.assign(data, {type, queryUrl});
接下來(lái)就可以構(gòu)建完整的iframe的src
let url = targetUrl + "?" + serialize(data); //雖然叫url但實(shí)際是iframe的src
然后我們封裝一個(gè)建立frame的方法。
function createIframe(url, cb) { let iframe = document.createElement("iframe"); iframe.style.display = "none"; iframe.src = url; document.body.appendChild(iframe); function handleIframe(e) { cb(e.data); document.body.removeChild(iframe); window.removeEventListener("message", handleIframe); } window.addEventListener("message", handleIframe); }
在這個(gè)方法中,我們創(chuàng)建了一個(gè)iframe設(shè)置其display為none使其不可見(jiàn),設(shè)置了其src,并且把它添加到了頁(yè)面上。又給window添加了事件監(jiān)聽(tīng),當(dāng)收到b頁(yè)面?zhèn)鱽?lái)的數(shù)據(jù)之后,調(diào)用數(shù)據(jù)處理的函數(shù)cb并且傳入數(shù)據(jù)作為其參數(shù)。當(dāng)cb執(zhí)行完畢之后,移除iframe,并移除事件監(jiān)聽(tīng)。
b頁(yè)面中我們的任務(wù)是,拿到location.search的并正確的解析為一個(gè)對(duì)象,該對(duì)象包含了{(lán)type,queryUrl,data} 其中type是ajax的類型,queryUrl是ajax的目標(biāo)url,data是請(qǐng)求的參數(shù)。
通過(guò)一個(gè)parseSearch的方法解析location.search。
function parseSearch() { let search = location.search.slice(1); let keyValuePairArr = search.split("&"); let obj = {}; keyValuePairArr.forEach(pair => { let [key, value] = pair.split("="); obj[decodeURIComponent(key)] = decodeURIComponent(value); }); return obj; }
我們還需要一個(gè)方法來(lái)移除其中的type和queryUrl,只剩下ajax請(qǐng)求的參數(shù)。
function getParams(obj) { delete obj.type; delete obj.queryUrl; return obj; }
然后我們就可以解析location.search得到信息對(duì)象,并且發(fā)出ajax請(qǐng)求來(lái)拿到服務(wù)器的數(shù)據(jù)了。
$.ajax({ type: obj.type, url: obj.queryUrl, data: getParams(obj) }).done(data => { window.parent.postMessage(data, "*"); });
再次鞏固一下整個(gè)流程,domain1下的a頁(yè)面向domain2發(fā)出動(dòng)態(tài)ajax請(qǐng)求的中間過(guò)程:
在a頁(yè)面下封裝b頁(yè)面完整url,ajax請(qǐng)求的type,ajax請(qǐng)求的最終url,以及ajax請(qǐng)求的數(shù)據(jù)等信息。通過(guò)設(shè)置iframe的src將這些信息帶到b頁(yè)面,b頁(yè)面解析這些信息,最后向服務(wù)器發(fā)出ajax請(qǐng)求并將結(jié)果通過(guò)postMessage的API帶回給a頁(yè)面,a頁(yè)面收到數(shù)據(jù)后處理數(shù)據(jù),處理完畢移除iframe,移除事件監(jiān)聽(tīng)。
除了利用postMessage API之外,還可以通過(guò)iframe + window.name來(lái)實(shí)現(xiàn)跨域ajax請(qǐng)求。
當(dāng)a頁(yè)面中有一個(gè)b頁(yè)面的iframe時(shí),兩個(gè)頁(yè)面共享window.name。在b頁(yè)面拿到數(shù)據(jù)后賦值給window.name。但是由于不使用postMessage API,數(shù)據(jù)無(wú)法傳輸給a頁(yè)面。我們可以將location.href轉(zhuǎn)為domain1(a頁(yè)面所在的域名)下的c頁(yè)面,由c頁(yè)面調(diào)用a頁(yè)面的回調(diào)方法。
先舉一個(gè)簡(jiǎn)單的例子:
a頁(yè)面:
Title
b頁(yè)面:
Title
c頁(yè)面:
Title
很簡(jiǎn)單的例子,a頁(yè)面中定義一個(gè)方法print,并嵌入一個(gè)frame,frame為b頁(yè)面,b頁(yè)面向服務(wù)器拿到數(shù)據(jù)后,賦值給window.name,然后再打開(kāi)c頁(yè)面,在c頁(yè)面調(diào)用父頁(yè)面a中的print方法,并將拿到的數(shù)據(jù)作為參數(shù)傳入。
不知道為啥,ajax請(qǐng)求返回的對(duì)象不經(jīng)處理直接賦值最終輸出結(jié)果是[object Object]。因此在這里先stringify之后再parse。
封裝之后的代碼如下:
aa頁(yè)面:
Title
bb頁(yè)面:
Title
c頁(yè)面:
Title
不同于使用postMessage,當(dāng)通過(guò)window.name通信時(shí),由于傳入的回調(diào)函數(shù)是在頁(yè)面c執(zhí)行,因此需要把回調(diào)函數(shù)的函數(shù)名作為參數(shù)傳過(guò)來(lái),并且也要把頁(yè)面c的url地址作為參數(shù)傳入。數(shù)據(jù)仍然是通過(guò)bb頁(yè)面獲得,bb頁(yè)面僅需向c頁(yè)面?zhèn)鬟ffuncName即可,c頁(yè)面拿到函數(shù)名,并通過(guò)window.name傳遞從服務(wù)器拿到的數(shù)據(jù),在c頁(yè)面執(zhí)行aa頁(yè)面的回調(diào)函數(shù),回調(diào)函數(shù)執(zhí)行完畢后移除aa頁(yè)面iframe以及該函數(shù)。
注意:不能在bb頁(yè)面直接調(diào)用parent頁(yè)面aa的函數(shù) 由于aa與bb是非同源的,因此會(huì)報(bào)錯(cuò)。必須由一個(gè)與aa頁(yè)面同源的頁(yè)面cc頁(yè)面,來(lái)執(zhí)行在aa頁(yè)面中注冊(cè)的函數(shù)。
以上是我所知道的iframe解決跨域ajax請(qǐng)求的兩種方法。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93179.html
摘要:如何利用網(wǎng)頁(yè)請(qǐng)求暴露出來(lái)的接口去抓取網(wǎng)頁(yè)數(shù)據(jù)很多爬蟲(chóng)都能實(shí)現(xiàn)這個(gè)功能??缬蛲ㄐ艜r(shí),瀏覽器會(huì)報(bào)如下錯(cuò)誤其實(shí)這兩個(gè)問(wèn)題都是由于跨域造成的。結(jié)果這些數(shù)據(jù)可以在請(qǐng)求成功會(huì)傳回本地。 如何利用網(wǎng)頁(yè)ajax請(qǐng)求暴露出來(lái)的接口去抓取網(wǎng)頁(yè)數(shù)據(jù)?很多爬蟲(chóng)都能實(shí)現(xiàn)這個(gè)功能。不過(guò)今天要來(lái)和大家八一八單從前端的角度,利用js解決這個(gè)問(wèn)題。 大家都知道,在不同域的情況下是不能發(fā)送ajax請(qǐng)求的,瀏覽器會(huì)報(bào)如下錯(cuò)...
摘要:跨域概述兩個(gè)不同域互相請(qǐng)求,稱為跨域,是由瀏覽器同源策略限制的一類請(qǐng)求場(chǎng)景。同源策略限制以下幾種行為和無(wú)法讀取無(wú)法獲得請(qǐng)求不能發(fā)送目前主流的用于解決跨域問(wèn)題的方法跨域缺點(diǎn)這種方法只適用于和窗口,和無(wú)法通過(guò)這種方法。 跨域概述 兩個(gè)不同域互相請(qǐng)求,稱為跨域,是由瀏覽器同源策略限制的一類請(qǐng)求場(chǎng)景。 --> 同源策略/SOP(Same origin policy)是瀏覽器最核心也最基本的安全...
摘要:前言原文地址前端跨域總結(jié)博主博客地址的個(gè)人博客相信每一個(gè)前端對(duì)于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。通過(guò)跨域前面說(shuō)過(guò)了,瀏覽器有一個(gè)同源策略,其限制之一是不能通過(guò)的方法去請(qǐng)求不同源中的文檔。 前言 原文地址:前端跨域總結(jié) 博主博客地址:Damonare的個(gè)人博客 相信每一個(gè)前端er對(duì)于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。但跨域方法的多種多樣實(shí)在讓人目...
摘要:前言原文地址前端跨域總結(jié)博主博客地址的個(gè)人博客相信每一個(gè)前端對(duì)于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。通過(guò)跨域前面說(shuō)過(guò)了,瀏覽器有一個(gè)同源策略,其限制之一是不能通過(guò)的方法去請(qǐng)求不同源中的文檔。 前言 原文地址:前端跨域總結(jié) 博主博客地址:Damonare的個(gè)人博客 相信每一個(gè)前端er對(duì)于跨域這兩個(gè)字都不會(huì)陌生,在實(shí)際項(xiàng)目中應(yīng)用也是比較多的。但跨域方法的多種多樣實(shí)在讓人目...
閱讀 601·2023-04-26 02:59
閱讀 718·2023-04-25 16:02
閱讀 2195·2021-08-05 09:55
閱讀 3634·2019-08-30 15:55
閱讀 4736·2019-08-30 15:44
閱讀 1823·2019-08-30 13:02
閱讀 2228·2019-08-29 16:57
閱讀 2316·2019-08-26 13:35