何為跨域?何為JSONP?JSONP技術能實現什么?是否有必要使用JSONP技術?
跨域
就是由于JavaScript同源策略的限制,使得a.com域名下的js無法操作b.com或c.a.com域名下的對象或數據。簡單理解同一個域就是:相同域名、相同端口、相同協議!
同源策略
就是阻止從一個域上加載的腳本獲取或操作另一個域上的文檔屬性。即受到請求的URL的域必須與當前Web頁面的域相同,意味著瀏覽器隔離來自不同源的內容,以防止它們之間的操作。
“同源策略”的意義
“同源策略”有效地阻止了一些危險行為,如你同時打開多個網站時,其中有一個木馬網站,那么木馬網站就有可能竊取其他網站上關于你的信息或資料(因為多個網站間是可以相互通信的),給網上用戶帶來很大的泄密風險。正是由于有了“同源策略”,才大大降低了這種風險,由于木馬網站與其他你瀏覽的網站不同源,因此無法相互間通信訪問、獲取數據等。
“同源策略”的不足
雖然“同源策略”在一定程度上保護了用戶的網絡安全,但如果有時就是需要讓www.aaa.com取得www.bbb.com上的數據,同樣是因為”同源策略”造成無法從自己信任的其他網頁上取得數據。
URL |
說明 |
是否允許通信 |
http://www.a.com/a.js |
同一域名下 |
允許 |
http://www.a.com/lab/a.js |
同一域名下不同文件夾 |
允許 |
http://www.a.com:8000/a.js |
同一域名,不同端口 |
不允許 |
http://www.a.com/a.js |
同一域名,不同協議 |
不允許 |
http://www.a.com/a.js |
域名和域名對應ip |
不允許 |
http://www.a.com/a.js |
主域相同,子域不同 |
不允許 |
http://www.a.com/a.js |
同一域名,不同二級域名 |
不允許 |
http://www.cnblogs.com/a.js |
不同域名 |
不允許 |
注意:
(1)如果是協議和端口造成的跨域問題,那么對于JavaScript來說是無能為力的。
(2)在跨域問題上,域僅僅是通過“URL首部”來識別而不會去判斷兩個域是否對應同一個IP地址。
JOSNP
為了解決上面提到的需求,JSONP應運而生。其實JSONP在一定程度上彌補了AJAX的不足,即無法跨域獲取數據。
那么JSONP這貨到底是怎么來的,總不會是一群工程師拍腦袋拍出來的吧?其實,任何技術、任何事情的來源都是有根源可尋的。
不知大家是否注意到,你是如何引用jQuery寫網頁的呢?是否就是在頁面中引入“<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>”即可,那么這其實是件很有意思的事情!大家是否發現http://code.jquery.com/與你的網站地址肯定是不同源的,那為什么還能在你的網頁中引用到jQuery呢?
是的,恍然大悟的時刻到了,其實JSONP就是利用這一點(可以算是漏洞、也可以算是技術吧)實現了跨域訪問數據。(其實有src屬性的不止<script>標簽,如<iframe>標簽也是能夠運用JSONP技術的)。說白了,其實JSONP跨域技術本質上是創建<script>標簽,并通過其src指向跨域地址而實現跨域獲取數據。
JSONP原理
JSONP(JSON with Padding),就是異步請求跨域的服務器端時,不是直接返回數據,而是返回一個js方法,把數據作為參數傳過來。如果只是跨域傳遞數據那么這種方式是比較好的。字面理解就是:利用內填充的原理,將json填充到一個box中的概念。
原理總是又饒又拗口,直接來個簡單的小例子吧!
在www.aaa.com 頁面中:
<script type="text/javascript" src="http://www.bbb.com/jsonp.js"></script> <script type="text/javascript"> function jsonp(json){ alert(json[‘name’]); } </script>
jsonp({'name':'twobin','age':24});
則頁面會彈出“twobin”,是否更為直觀好理解一點呢!
我們可以取到www.bbb.com/jsonp.js,里面是一個名為jsonp的函數(這個函數名稱可以自定義),這個函數也會被加載到www.aaa.com。加載完成后,就應該執行jsonp了,然后我們在www.aaa.com定義jsonp函數,這個函數里寫一些處理數據的語句。這樣其實就簡單地實現了跨域訪問數據了,這也就是JSONP的工作原理了。而“JSON with Padding”的意思,就是jsonp(json)中的json,即
{'name':'twobin','age':24}
這個JSON對象被包在jsonp這個函數中當作參數來被處理,而“JSON with Padding”這個詞很形象地形容了這個過程。
JSONP實例—百度搜索聯想
在百度首頁搜索框中其實就用到了JSONP技術,如我們在百度搜索框中輸入json,則下拉框會自動給出多個相關的聯想詞,而這些聯想詞其實是從另一個不同源的域名中獲取的數據,通過JSONP技術獲取這些數據后實時的顯示在下拉列表中。
本文就是仿百度搜索聯想實現一個采用JSONP技術的例子。
(1)解析數據地址
首先需要知道聯想詞數據的來源地址。在Chrome中的JavaScript控制臺下,查看Network,在百度搜索框中輸入關鍵詞,如“json”,則獲取到輸入“json”關鍵詞后傳回的數據。
其中,聯想詞數據的地址是:
http://suggestion.baidu.com/su?wd=json&p=3&cb=window.bdsug.sug&sid=&t=1383046774638
簡單解析下該地址,搜索關鍵字wd=‘json’,cb是一個回調函數,該回調函數是我們取到數據要后執行的函數,在百度搜索中回調后執行函數window.bdsug.sug。點擊該地址鏈接,可以得到下列數據:
window.bdsug.sug({q:"json",p:false,s:["json格式","json在線解析","json解析","jsonp","jsonobject","json編輯器","jsonarray","json encode","json.stringify","json decode"]});
即這些聯想詞數據包含在函數window.bdsug.sug內作為參數傳遞給百度搜索首頁,證明了JSONP跨域技術的可行性。
(2)動態獲取跨域數據
既然是利用<script>標簽的src地址來獲取跨域數據,就不能將src地址寫死,而應該根據需求動態獲取跨域數據,因此需要根據需求動態生成<script>標簽后動態指定src地址。
var oScript = document.createElement('script'); oScript.src = 'http://suggestion.baidu.com/su?wd='+oTxt.value+'&p=3&cb=baidu&from=superpage'; document.body.appendChild(oScript);
注意:動態生成<script>標簽時會產生代碼冗余,由于我們每輸入一個字符,頁面就會動態生成一個<script>標簽,一旦我們輸入的字符繁多且不同,頁面就會實時生成眾多的冗余標簽,因此需要在我們輸入字符前檢查是否存在冗余的<script>標簽,如果存在則將其刪除,從而避免代碼冗余。
if(oScript){ document.body.removeChild(oScript); }
有博友提問:Google中的搜索聯想貌似跟百度中的不一樣?
Google中的搜索聯想并不是通過callback回調函數執行的,如在google首頁搜索框中輸入“j”,則返回鏈接為:https://www.google.com.hk/complete/search?client=hp&hl=zh-CN&gs_rn=32&gs_ri=hp&cp=1&gs_id=65&q=j&xhr=t;顯然google中的搜索聯想是通過ajax技術實現無刷新實時返回聯想數據的。
效果展示
文章列表