JS、JQuery和ExtJs的跨域处理
1.什么是跨域?
跨域,JavaScript出于安全方面的考慮,不允許跨域調(diào)用其他頁面的對象。簡單地理解就是因?yàn)镴avaScript同源策略的限制,a.com 域名下的js無法操作b.com或是c.a.com域名下的對象。
同源策略,它是由Netscape提出的一個(gè)著名的安全策略。現(xiàn)在所有支持JavaScript 的瀏覽器都會(huì)使用這個(gè)策略。所謂同源是指,域名,協(xié)議,端口相同。當(dāng)一個(gè)瀏覽器的兩個(gè)tab頁中分別打開來 百度和谷歌的頁面當(dāng)一個(gè)百度瀏覽器執(zhí)行一個(gè)腳本的時(shí)候會(huì)檢查這個(gè)腳本是屬于哪個(gè)頁面的,即檢查是否同源,只有和百度同源的腳本才會(huì)被執(zhí)行。
更詳細(xì)的說明可以看下表:
| URL | 說明 | 是否允許通信 |
| http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允許 |
| http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下不同文件夾 | 允許 |
| http://www.a.com:8000/a.js http://www.a.com/b.js | 同一域名,不同端口 | 不允許 |
| http://www.a.com/a.js https://www.a.com/b.js | 同一域名,不同協(xié)議 | 不允許 |
| http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名對應(yīng)ip | 不允許 |
| http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允許 |
| http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二級域名(同上) | 不允許(cookie這種情況下也不允許訪問 |
| http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允許 |
特別注意兩點(diǎn):
(1).如果是協(xié)議和端口造成的跨域問題“前臺”是無能為力的,
(2).在跨域問題上,域僅僅是通過“URL的首部”來識別而不會(huì)去嘗試判斷相同的ip地址對應(yīng)著兩個(gè)域或兩個(gè)域是否在同一個(gè)ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解為“Domains, protocols and ports must match”。
2.跨域請求數(shù)據(jù)解決方案
(1).document.domain+iframe的設(shè)置
對于主域相同而子域不同的例子,可以通過設(shè)置document.domain的辦法來解決。
(2).動(dòng)態(tài)創(chuàng)建Script
雖然瀏覽器默認(rèn)禁止了跨域訪問,但并不禁止在頁面中引用其他域的JS文件,并可以自由執(zhí)行引入的JS文件中的function(包括操作cookie、Dom等等)。
(3).利用iframe和location.hash
這個(gè)辦法比較繞,但是可以解決完全跨域情況下的腳步置換問題。原理是利用location.hash來進(jìn)行傳值。
(4).Window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸
iframe的src屬性由外域轉(zhuǎn)向本地域,跨域數(shù)據(jù)即由iframe的window.name從外域傳遞到本地域。這個(gè)就巧妙地繞過了瀏覽器的跨域訪問限制,但同時(shí)它又是安全操作。
(5).使用HTML5 postMessage
HTML5中最酷的新功能之一就是 跨文檔消息傳輸Cross Document Messaging。
(6).利用flash
上述,六種方式都可以處理JavaScript的跨域請求數(shù)據(jù)問題,詳細(xì)參見:Rain Man的《JavaScript跨域總結(jié)與解決辦法》。
除了上面六種方式,大家平時(shí)估計(jì)都在用腳本框架開發(fā),在JQuery框架和ExtJs框架中處理JS跨域問題,常用JSONP來處理。
3.什么是JSONP?
JSONP(JSON with Padding)是一個(gè)非官方的協(xié)議,它允許在服務(wù)器端集成Script Tags返回至客戶端,通過Javascript callback的形式實(shí)現(xiàn)跨域訪問(這僅僅是JSONP簡單的實(shí)現(xiàn)形式)。
由于同源策略的限制,XMLHttpRequest只允許請求當(dāng)前源(域名、協(xié)議、端口)的資源,為了實(shí)現(xiàn)跨域請求,可以通過script標(biāo)簽實(shí)現(xiàn)跨域請求,然后在服務(wù)端輸出JSON數(shù)據(jù)并執(zhí)行回調(diào)函數(shù),從而解決了跨域的數(shù)據(jù)請求。
4..JSONP如何產(chǎn)生的?
(1).跨域訪問無權(quán)限。
眾所周知的問題,Ajax直接請求普通文件存在跨域無權(quán)限訪問的問題,不管是靜態(tài)頁面、動(dòng)態(tài)網(wǎng)頁、web服務(wù)、WCF,只要是跨域請求,都無權(quán)限;
(2)."src"屬性標(biāo)簽有跨域能力。
發(fā)現(xiàn)在Web頁面上調(diào)用js文件時(shí)則不受是否跨域的影響(不僅如此,擁有"src"屬性的標(biāo)簽都擁有跨域能力,比如<script>、<img>、<iframe>);
(3).將數(shù)據(jù)裝進(jìn)JS格式數(shù)據(jù)。
如果想通過純Web端(ActiveX控件、服務(wù)端代理、HTML5之Websocket等方式不算)跨域訪問數(shù)據(jù)就只有一種可能,就是在遠(yuǎn)程服務(wù)器上設(shè)法把數(shù)據(jù)裝進(jìn)js格式的數(shù)據(jù)里,供客戶端調(diào)用和進(jìn)一步處理;
(4).JSON格式承載數(shù)據(jù)適合。
有一種JSON的純字符數(shù)據(jù)格式可以簡潔的描述復(fù)雜數(shù)據(jù),更妙的是JSON還被JS原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數(shù)據(jù);
(5).動(dòng)態(tài)生成JSON格式數(shù)據(jù)。
Web客戶端可以通過與調(diào)用腳本一模一樣的方式,來調(diào)用跨域服務(wù)器上動(dòng)態(tài)生成的js格式文件,顯而易見,服務(wù)器之所以要?jiǎng)討B(tài)生成JSON文件,目的在于把客戶端需要的數(shù)據(jù)裝入進(jìn)去。
(6).JSON數(shù)據(jù)成功回調(diào)到客戶端。
客戶端在對JSON文件調(diào)用成功之后,也就獲得了自己所需的數(shù)據(jù),剩下的就是按照自己需求進(jìn)行處理和展現(xiàn)了,這種獲取遠(yuǎn)程數(shù)據(jù)的方式看起來非常像AJAX,但實(shí)質(zhì)上是不一樣。
(7).形成一種非正式傳輸協(xié)議JSONP。
為了便于客戶端使用數(shù)據(jù),逐漸形成了一種非正式傳輸協(xié)議,人們把它稱作JSONP,該協(xié)議的一個(gè)要點(diǎn)就是允許用戶傳遞一個(gè)callback參數(shù)給服務(wù)端,然后服務(wù)端返回?cái)?shù)據(jù)時(shí)會(huì)將這個(gè)callback參數(shù)作為函數(shù)名來包裹住JSON數(shù)據(jù),這樣客戶端就可以隨意定制自己的函數(shù)來自動(dòng)處理返回的數(shù)據(jù)。
5.JSONP的工作原理
JSONP的原理:創(chuàng)建一個(gè)回調(diào)函數(shù),動(dòng)態(tài)創(chuàng)建Script標(biāo)簽,然后在遠(yuǎn)程服務(wù)上調(diào)用這個(gè)函數(shù)并且將JSON 數(shù)據(jù)形式作為參數(shù)傳遞,完成回調(diào)。將JSON數(shù)據(jù)填充進(jìn)回調(diào)函數(shù),進(jìn)行相關(guān)的邏輯處理,或許這就是JSONP的JSON+Padding的含義。
(1).跨域簡單原理
新建一個(gè)asp.net的web程序,添加sample.html網(wǎng)頁和一個(gè)test.js文件,代碼如下:
sample.html的代碼:
test.js的代碼:
打開sample.html后會(huì)跳出"success”這樣的這樣的信息框,這似乎并不能說明什么, 跨域問題到底怎么解決呢?
現(xiàn)在模擬非同源的環(huán)境,把上面的Web程序叫做A程序,再新建一個(gè)Web程序叫做B程序,將A程序的test.js文件移除然后拷貝到B程序中。將兩個(gè)程序都運(yùn)行起來,Visual Studio會(huì)啟動(dòng)內(nèi)置服務(wù)器,假設(shè)A程序是localhost:20001,B程序是localhost:20002,這就模擬了一個(gè)非同源的環(huán)境了(雖然域名相同但端口號不同,所以是非同源的)。
現(xiàn)在改下A程序sample.html里的代碼,因?yàn)閠est.js文件在B程序上了,url也就變成了localhost:20002。
sample.html部分代碼:
<script type="text/javascript" src="http://localhost:20002/test.js"></script>請保持AB兩個(gè)Web程序的運(yùn)行狀態(tài),當(dāng)你再次刷新A程序localhost:20001/sample.html的時(shí)候,和原來一樣跳出了"success"的對話框,這樣就成功訪問到了非同源的B程序localhost:20002/test.js這個(gè)所謂的遠(yuǎn)程服務(wù)了。到這里,大家應(yīng)該已經(jīng)大概明白如何跨域訪問的原理了。
<script>標(biāo)簽的src屬性并不被同源策略所約束,所以可以獲取任何服務(wù)器上腳本并執(zhí)行。
(2).跨域?qū)崿F(xiàn)CallBack
繼續(xù)修改代碼,實(shí)現(xiàn)JSONP的JavaScript callback形式。
修改程序A中sample的代碼:
程序B中test.js的代碼:
//調(diào)用callback函數(shù),并以json數(shù)據(jù)形式作為闡述傳遞,完成回調(diào) callback({message:"success"});這其實(shí)就是JSONP的簡單實(shí)現(xiàn)模式,或者說是JSONP的原型:創(chuàng)建一個(gè)回調(diào)函數(shù),然后在遠(yuǎn)程服務(wù)上調(diào)用這個(gè)函數(shù)并且將JSON 數(shù)據(jù)形式作為參數(shù)傳遞,完成回調(diào)。
(3).跨域?qū)崿F(xiàn)動(dòng)態(tài)JS腳本
怎么讓遠(yuǎn)程js知道它應(yīng)該調(diào)用的本地函數(shù)叫什么名字?畢竟是jsonp的服務(wù)者都要面對很多服務(wù)對象,而這些服務(wù)對象各自的本地函數(shù)都不相同。只要服務(wù)端提供的js腳本是動(dòng)態(tài)生成的就可以,這樣調(diào)用者可以傳一個(gè)參數(shù)過去告訴服務(wù)端“我想要一段調(diào)用XXX函數(shù)的js代碼,請你返回給我”,于是服務(wù)器就可以按照客戶端的需求來動(dòng)態(tài)生成js腳本并響應(yīng)了。
程序A中sample的代碼:
這樣不直接把遠(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ù)中供本地調(diào)用。
程序B中test.js的代碼:
我們看到,傳遞給flightHandler函數(shù)的是一個(gè)json,它描述了航班的基本信息。運(yùn)行一下頁面,成功彈出提示窗口,jsonp的執(zhí)行全過程順利完成!
6.JQuery和ExtJs實(shí)現(xiàn)JSONP
(1).JQuery的JSONP跨域?qū)崿F(xiàn)
<1>.$.getJSON
jQuery框架支持JSONP,可以使用$.getJSON(url,[data],[callback])方法(詳細(xì)可以參考http://api.jquery.com/jQuery.getJSON/)。繼續(xù)修改程序A的代碼,改用jQuery的getJSON方法來實(shí)現(xiàn)(下面的例子沒用用到向服務(wù)傳參,所以只寫了getJSON(url,[callback])):
要注意的是在url的后面必須添加一個(gè)callback參數(shù),這樣getJSON方法才會(huì)知道是用JSONP方式去訪問服務(wù),callback后面的那個(gè)問號是內(nèi)部自動(dòng)生成的一個(gè)回調(diào)函數(shù)名。這個(gè)函數(shù)名可以debug看一下,比如jQuery17207481773362960666_1332575486681。
<2>.$.ajax
假如說我們想指定自己的回調(diào)函數(shù)名,或者說服務(wù)上規(guī)定了固定回調(diào)函數(shù)名該怎么辦呢?可以使用$.ajax方法來實(shí)現(xiàn)(參數(shù)較多,詳細(xì)可以參見http://api.jquery.com/jQuery.ajax)。
jsonpCallback就是指定我們自己的回調(diào)方法名person,遠(yuǎn)程服務(wù)接受callback參數(shù)的值就不再是自動(dòng)生成的回調(diào)名,而是person。dataType是指定按照J(rèn)SOPN方式訪問遠(yuǎn)程服務(wù)。
(2).ExtJs的JSONP跨域?qū)崿F(xiàn)
<1>.Ext.data.JsonP.request
ExtJS4.1的Ext.data.JsonP.request實(shí)現(xiàn)跨域訪問:
其中跨域請求的要點(diǎn)是類名:Ext.data.JsonP和callbackKey的參數(shù)。
“jsonPCallback”該名稱將作為Jsonp請求的方法名傳遞到服務(wù)器端,獲取該請求的URL:
http://10.0.13.64:89/Home/InitializeComet?loginId=0001&jsonPCallback=Ext.data.JsonP.callback1&_dc=1370687739484
<2>.Ext.data.ScriptTagProxy
?
Ext.Ajax.request({url: 'http://10.128.3.104/edi/rest/GetBillCaseInfo',//url: 'testjson.do',scriptTag: true,success: function (req) {alert(req.responseText);},failure: function (req) {alert(req.responseText);},headers: { 'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=' },params: { _out: 'json' } });7.AJAX與JSONP的異同
(1).Ajax和Jsonp是兩種技術(shù)。
Ajax和Jsonp這兩種技術(shù)在調(diào)用方式上“看起來”很像,目的也一樣,都是請求一個(gè)URL,然后把服務(wù)器返回的數(shù)據(jù)進(jìn)行處理,因此JQuery和EXT等框架都把Jsonp作為Ajax的一種形式進(jìn)行了封裝;
(2).Ajax和Jsonp實(shí)現(xiàn)原理不同。
Ajax和Jsonp在本質(zhì)實(shí)現(xiàn)上有差別。Ajax的核心是通過XmlHttpRequest獲取非本頁內(nèi)容,而Jsonp的核心則是動(dòng)態(tài)添加<script>標(biāo)簽來調(diào)用服務(wù)器提供的js腳本。所以說,其實(shí)Ajax與jsonp的區(qū)別不在于是否跨域,ajax通過服務(wù)端代理一樣可以實(shí)現(xiàn)跨域,Jsonp本身也不排斥同域的數(shù)據(jù)的獲取;
(3).Ajax和Jsonp都是非強(qiáng)制性協(xié)議。
Jsonp是一種方式或者說非強(qiáng)制性協(xié)議,如同Ajax一樣,它也不一定非要用Json格式來傳遞數(shù)據(jù),如果你愿意,字符串都行,只不過這樣不利于用Jsonp提供公開服務(wù)。
總而言之,Jsonp不是Ajax的一個(gè)特例,哪怕Jquery、Ext等巨頭把Jsonp封裝進(jìn)了Ajax,也不能改變這一點(diǎn)!
參考博客:
《Ajax與JSON的一些總結(jié)》
《JavaScript跨域總結(jié)與解決辦法》
《深入淺出JSONP--解決ajax跨域問題》
《說說JSON和JSONP,也許你會(huì)豁然開朗,含jQuery用例》
《Jquery跨域請求》
《ExtJs學(xué)習(xí)筆記(23)-ScriptTagProxy+XTemplate+WCF跨域取數(shù)據(jù)》
《ExtJs與WCF之間的跨域訪問》
《jQuery與Extjs的Ajax的跨域訪問》
轉(zhuǎn)載于:https://www.cnblogs.com/SanMaoSpace/p/3144851.html
總結(jié)
以上是生活随笔為你收集整理的JS、JQuery和ExtJs的跨域处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# Socket编程(3)编码和解码
- 下一篇: ExtJS参考手册