常見的javascript跨域通信方法
本文主要介紹幾種常見的javascript跨域通信方法。首先講解一下JSONP。
1、JSONP
JSONP(JSON with Padding)是JSON的一種“使用模式”,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。由于同源策略,一般來說位于 server1.example.com 的網(wǎng)頁無法與不是 server1.example.com的服務(wù)器溝通,而 HTML 的<script> 元素是一個(gè)例外。利用 <script> 元素的這個(gè)開放策略,網(wǎng)頁可以得到從其他來源動(dòng)態(tài)產(chǎn)生的 JSON 資料,而這種使用模式就是所謂的 JSONP。用 JSONP 抓到的資料并不是JSON,而是任意的JavaScript,用 JavaScript 直譯器執(zhí)行而不是用 JSON 解析器解析。
下面我們來介紹下JSONP的具體實(shí)現(xiàn)。
我們知道,哪怕跨域js文件中的代碼(當(dāng)然指符合web腳本安全策略的),web頁面也是可以無條件執(zhí)行的。遠(yuǎn)程服務(wù)器remoteserver.com根目錄下有個(gè)remote.js文件代碼如下:
alert('我是遠(yuǎn)程文件');
本地服務(wù)器localserver.com下有個(gè)jsonp.html頁面代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script> </head> <body> </body> </html>
毫無疑問,頁面將會彈出一個(gè)提示窗體,顯示跨域調(diào)用成功。
現(xiàn)在我們在jsonp.html頁面定義一個(gè)函數(shù),然后在遠(yuǎn)程remote.js中傳入數(shù)據(jù)進(jìn)行調(diào)用。jsonp.html頁面代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> var localHandler = function(data){ alert('我是本地函數(shù),可以被跨域的remote.js文件調(diào)用,遠(yuǎn)程js帶來的數(shù)據(jù)是:' + data.result); }; </script> <script type="text/javascript" src="http://remoteserver.com/remote.js"></script> </head> <body> </body> </html>
remote.js文件代碼如下:
localHandler({"result":"我是遠(yuǎn)程js帶來的數(shù)據(jù)"});
成功運(yùn)行,看來跨域遠(yuǎn)程獲取數(shù)據(jù)的目的實(shí)現(xiàn)了,但是又一個(gè)問題出現(xiàn)了,我怎么讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字呢?這時(shí)我們就需要將服務(wù)端提供的js腳本動(dòng)態(tài)生成就行了,調(diào)用者可用通過傳參告訴服務(wù)端自己需要什么函數(shù),jsonp.html的代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> // 得到航班信息查詢結(jié)果后的回調(diào)函數(shù) var flightHandler = function(data){ alert('你查詢的航班結(jié)果是:票價(jià) ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 張。'); }; // 提供jsonp服務(wù)的url地址(不管是什么類型的地址,最終生成的返回值都是一段javascript代碼) var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler"; // 創(chuàng)建script標(biāo)簽,設(shè)置其屬性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script標(biāo)簽加入head,此時(shí)調(diào)用開始 document.getElementsByTagName('head')[0].appendChild(script); </script> </head> <body> </body> </html>
這次的代碼變化比較大,不再直接把遠(yuǎn)程js文件寫死,而是編碼實(shí)現(xiàn)動(dòng)態(tài)查詢,而這也正是jsonp客戶端實(shí)現(xiàn)的核心部分,本例中的重點(diǎn)也就在于如何完成jsonp調(diào)用的全過程。
我們看到調(diào)用的url中傳遞了一個(gè)code參數(shù),告訴服務(wù)器我要查的是CA1998次航班的信息,而callback參數(shù)則告訴服務(wù)器,我的本地回調(diào)函數(shù)叫做flightHandler,所以請把查詢結(jié)果傳入這個(gè)函數(shù)中進(jìn)行調(diào)用。這個(gè)叫做flightResult.aspx的頁面生成了一段這樣的代碼提供給jsonp.html(服務(wù)端的實(shí)現(xiàn)這里就不演示了,與你選用的語言無關(guān),說到底就是拼接字符串):
flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5 });
傳遞給flightHandler函數(shù)的是一個(gè)json,它描述了航班的基本信息。運(yùn)行一下頁面,成功彈出提示窗口,jsonp的執(zhí)行全過程順利完成!
但是JSONP存在一點(diǎn)問題,就是由遠(yuǎn)程服務(wù)端負(fù)責(zé)包裝json數(shù)據(jù),并調(diào)用命名函數(shù),這種方式存在安全隱患,在使用JSONP時(shí),必須完全信任服務(wù)端所提供的數(shù)據(jù),惡意腳本就可以直接接管我們的應(yīng)用。所以接下來我們要介紹一種別的方式,來避免這種安全隱患。
2、CORS
CORS(Cross OriginResource Sharing,跨源資源共享)實(shí)現(xiàn)了跨源XMLHttpRequests,跨源HTTP請求包括一個(gè)Origin頭部,它為服務(wù)器提供HTTP請求的源信息。頭部由瀏覽器保護(hù),不能被應(yīng)用程序代碼更改。這種方式遠(yuǎn)比評估外部輸入的方式安全。
以前的ajax只能同源請求,現(xiàn)在通過XMLHttpRequests二級,可以進(jìn)行跨域請求。假設(shè)我們頁面或者應(yīng)用已在 http://www.test1.com 上了,而我們打算從 http://www.test2.com 請求提取數(shù)據(jù)。一般情況下,如果我們直接使用 AJAX 來請求將會失敗,瀏覽器也會返回“源不匹配”的錯(cuò)誤,"跨域"也就以此由來。
利用 CORS,http://www.test2.com 只需添加一個(gè)標(biāo)頭,就可以允許來自 http://www.test1.com 的請求。php代碼如下:
header("Access-Comtrol-Allow-Origin:*");<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
其中*表示允許任何域向我們的服務(wù)端提交請求。也可以設(shè)置指定的域名,代碼如下:
header("Access-Control-Allow-Origin:http://www.test2.com");
設(shè)置好頭信息之后,其他域就可以進(jìn)行請求了。
使用"跨域資源共享"的前提,是瀏覽器必須支持這個(gè)功能,而且服務(wù)器端必須同意這種"跨域"。如果能夠滿足上面的條件,則代碼的寫法與不跨域的請求完全一樣。
xhr.open('GET', ' http://www.test2.com ');
接下來介紹另外一種實(shí)時(shí)通信方式:
3、Cross-document messaging
跨文檔信息通信。使用這個(gè)功能,只要獲取到網(wǎng)頁所在窗口對象的實(shí)例,不僅同原的web網(wǎng)頁可以互相通信,也可以實(shí)現(xiàn)跨域通信。要想接受從其他窗口發(fā)送來的信息,必須對窗口對象的onmessage事件進(jìn)行監(jiān)聽,其他窗口可以通過postmessage方法來傳遞數(shù)據(jù),該方法使用兩個(gè)參數(shù):第一個(gè)參數(shù)為所發(fā)送的消息文本,但也可以是任何js對象,第二個(gè)參數(shù)為接收消息的對象窗口的url地址。
下面進(jìn)行試驗(yàn),主頁面index.html代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <script type="text/javascript"> function sendIt(){ document.getElementById("otherPage").contentWindow .postMessage(//向子窗口發(fā)出請求 document.getElementById("message").value,//值 "http://127.0.0.1:8020"http://目標(biāo)域 ) } </script> <body> <iframe src="http://127.0.0.1:8020/test2/JS/jstest/Cross-document-messaging/other.html" id="otherPage" width="" height=""></iframe> <br /><br /> <input type="text" name="message" id="message" value="" /> <input type="button" name="" id="" value="發(fā)送跨域消息" onclick="sendIt();" /> </body> </html>
窗口所引用頁面other.html代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script type="text/javascript"> window.addEventListener("message",function(event){//通過onmessage監(jiān)聽 //將從父窗口傳來的數(shù)據(jù)展現(xiàn)出來 document.getElementById("content").innerHTML+=event.data+"<br>"; },false); </script> </head> <body> 信息來自于另外一個(gè)域 <div id="content"> </div> </body> </html>
試驗(yàn)結(jié)果如下:
可以看到在81端口服務(wù)器中的index.html和8020端口的服務(wù)器中的other.html進(jìn)行的通信。
完整代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <script type="text/javascript"> function sendIt(){ document.getElementById("otherPage").contentWindow .postMessage(//向子窗口發(fā)出請求 document.getElementById("message").value,//值 "http://127.0.0.1:8020"http://目標(biāo)域 ) } </script> <body> <iframe src="http://127.0.0.1:8020/test2/JS/jstest/Cross-document-messaging/other.html" id="otherPage" width="" height=""></iframe> <br /><br /> <input type="text" name="message" id="message" value="" /> <input type="button" name="" id="" value="發(fā)送跨域消息" onclick="sendIt();" /> </body> </html>
CrossDocumentMessaging_index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script type="text/javascript"> window.addEventListener("message",function(event){//通過onmessage監(jiān)聽 //將從父窗口傳來的數(shù)據(jù)展現(xiàn)出來 document.getElementById("content").innerHTML+=event.data+"<br>"; },false); </script> </head> <body> 信息來自于另外一個(gè)域 <div id="content"> </div> </body> </html>
以上就是本文的全部內(nèi)容,希望對大家了解熟悉常見的javascript跨域通信方法有所幫助。
相關(guān)文章
通過javascript實(shí)現(xiàn)掃雷游戲代碼實(shí)例
這篇文章主要介紹了通過javascript實(shí)現(xiàn)掃雷游戲代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02獲取3個(gè)數(shù)組不重復(fù)的值的具體實(shí)現(xiàn)
先用concat拼接數(shù)組 ,再使用一個(gè)對象、一個(gè)新數(shù)組(用于存放不重復(fù)的數(shù)組)具體實(shí)現(xiàn)如下,感興趣的朋友可以參考2013-12-12JavaScript實(shí)現(xiàn)隱藏省略文字效果的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)隱藏省略文字效果的方法,涉及javascript基于事件響應(yīng)實(shí)現(xiàn)頁面字符串元素的獲取、截取、設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2017-04-04javascript關(guān)于open.window子頁面執(zhí)行完成后刷新父頁面的問題分析
這篇文章主要介紹了javascript關(guān)于open.window子頁面執(zhí)行完成后刷新父頁面的問題,實(shí)例分析了javascript操作子頁面的執(zhí)行與父頁面的刷新技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04javaScript事件學(xué)習(xí)小結(jié)(四)event的公共成員(屬性和方法)
這篇文章主要介紹了javaScript事件學(xué)習(xí)小結(jié)(四)event的公共成員(屬性和方法)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06改版了網(wǎng)上的一個(gè)js操作userdata
改版了網(wǎng)上的一個(gè)js操作userdata,并根據(jù)其它網(wǎng)友的文章結(jié)合了下。希望對需要的朋友有所幫助。2007-04-04JavaScript實(shí)現(xiàn)換膚效果(換背景)
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)換膚效果,即換背景功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09