憨厚生

          ----Java's Slave----
          ***Java's Host***

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            165 隨筆 :: 17 文章 :: 90 評論 :: 0 Trackbacks
          轉 http://www.cn-cuckoo.com/2008/09/13/the-origin-of-jsonp-262.html

          瀏覽器安全模型規定,XMLHttpRequest、框架(frame)等只能在一個域中通信。從安全角度考慮,這個規定很合理;但是,也確實給分布式(面向服務、混搭等等本周提到的概念)Web開發帶來了麻煩。

          為了實現跨域通信,通常的解決方案有3種:

          本地代理:
          需要一些硬件設施(沒有服務器的客戶端無法運行),并且帶寬和潛伏時間也要加倍(遠程服務器-代理服務器-客戶端)。

          Flash:
          遠程主機中需要部署一個crossdomain.xml文件,而且,Flash作為一門專有技術,其前途尚不明朗;換句話說,開發人員很可能要學習一種目標不確定的編程語言。

          Script標簽:
          無法確切知道內容是否有效,沒有標準的實現方法,又可能被認為是一種“安全風險”。


          在此,我建議使用一種新技術,也是一種獨立于標準的方法,即通過script標簽來跨域獲取數據,名為JSON with Padding,或者就叫JSONP。JSONP的原理很簡單,但需要服務器端給予相應配合。大致來說,JSONP的實現思路就是在客戶端編程時作好使用JSON數據的準備,然后再通過圓括號將這些數據括起來以創建一條有效的JavaScript語句(可能是一次有效的函數調用)。

          也就是說,客戶端可以使用一個用于命名jsonp的查詢參數來決定可以獲取的數據。最簡單的情況下,如果jsonp參數為空,則返回的數據就是被括在圓括號中的JSON。

          下面,我們就以del.icio.us的JSON API為例,來說明JSONP的原理。該API有一個“script tag”變量(即,可以將下面的URL作為script標簽的src屬性值,用以加載del.icio.us這個API提供的數據。——譯者注)如下所示:

          http://del.icio.us/feeds/json/bob/mochikit+interpreter:

          1. if(typeof(Delicious) == 'undefined') Delicious = {};
          2. Delicious.posts = [{
          3. "u": "http://mochikit.com/examples/interpreter/index.html",
          4. "d": "Interpreter - JavaScript Interactive Interpreter",
          5. "t": [
          6. "mochikit","webdev","tool","tools",
          7. "javascript","interactive","interpreter","repl"
          8. ]
          9. }]

          如果用JSONP的方式來表示,那么與此具有相同語義的URL應該是這樣的:

          http://del.icio.us/feeds/json/bob/mochikit+interpreter?
          jsonp=if(typeof(Delicious)%3D%3D%27undefined%27)
          Delicious%3D%7B%7D%3BDelicious.posts%3D

          單純看這個URL似乎沒有什么,但我們可以要求服務器在數據有效時給出通知。因此,我可以編寫一個用于跟蹤數據的小系統:

          1. var delicious_callbacks = {};
          2. function getDelicious(callback, url) {
          3. var uid = (new Date()).getTime();
          4. delicious_callbacks[uid] = function () {
          5. delete delicious_callbacks[uid];
          6. callback();
          7. };
          8. url += "?jsonp=" + encodeURIComponent("delicious_callbacks[" + uid + "]");
          9. // 手工輸入代碼,向文檔中插入script標簽
          10. };
          11.  
          12. getDelicious(doSomething, "http://del.icio.us/feeds/json/bob/mochikit+interpreter");

          根據以上假設,用于獲取數據的URL應該如下所示:
          http://del.icio.us/feeds/json/bob/mochikit+interpreter?jsonp=delicious_callbacks%5B12345%5D

          1. delicious_callbacks[12345]([{
          2. "u": "http://mochikit.com/examples/interpreter/index.html",
          3. "d": "Interpreter - JavaScript Interactive Interpreter",
          4. "t": [
          5. "mochikit","webdev","tool","tools",
          6. "javascript","interactive","interpreter","repl"
          7. ]
          8. }])

          可見,由于使用圓括號括住了返回的數據,這就相當于把一個JSONP請求轉化成了一次函數調用,或者得到了一個純粹的JSON直接量。服務器所要配合做的,就是在JSON數據的開頭添加一小段文本(即回調函數的名稱。——譯者注)并將JSON數據放在括號中!

          當然,接下來最好是使用Mochikit、Dojo等框架來抽象JSONP,從而讓自己省去動手編寫DOM以插入script標簽的麻煩。

          沒錯,JSONP只是解決了標準化的問題。假如遠程主機想通過script標簽向頁面中注入惡意代碼,而不是返回JSON數據,那么頁面安全可能會 隨時受到威脅。不過,一旦實現了JSONP,那么對開發人員來說肯定是一件省時省力的大好事,在此基礎上各種一般化的抽象、教程及文檔也會應運而生的。

          注:縮寫詞 JSONP 由 Bob Ippolito 在一篇名為 “Remote JSON - JSONP” 的文章中提出。但許多支持以 JSONP 技術實現跨域通信的廠商沒有稱其為 JSONP。例如,雅虎公司就稱這種技術為 “JSON with callbacks”。另外,原文發表于2005年12月5日。

          留言(9)

          hello cuckoo九月 16th, 2008 at 9:42 上午

          中秋好。
          怎么把我的鏈接去掉了呢?
          給我做個鏈接可以嗎???
          非常感謝!!
          我的EMAIL:hardcometure@163.com

          vampire九月 16th, 2008 at 8:41 下午

          大概是說通過script的src來實現跨域,通過經編碼的json在url中傳遞數據?
          是不是說頁面上的js生產帶有不同參數的jsonp,通過src傳遞給服務端,服務端根據該jsonp返回相應數據?有點不太明白,能否提供一個實例?謝謝

          admin九月 17th, 2008 at 8:43 下午

          @vampire

          你的理解是對的,看來我的翻譯你能看明白,呵呵。使用JSONP技術時,一般是由JS在客戶端頁面中動態插入script標簽,將其src屬性設置 為帶參數的URL。當頁面加載時,前述URL會將參數通過GET請求發送到相應服務器端應用程序(由URL表示),服務器根據參數返回數據——注意,這個 數據格式是JSON,并且(注意)被包含在一個函數調用中,例如:callback({json_data})。這樣,在客戶端頁面中存在預定義的 callback(data)函數的定義時,服務器返回的函數調用就會立即執行,由客戶端的函數對數據進行操作。

          實際的例子有很多,如Yahoo Search、Google Base、Flickr Search、Amazon Search等等。要學習和使用這些站點提供的支持JSONP的API,一般要注意兩點:一是有的站點要求注冊密鑰(使用時必須放到參數中),二是要注意 參數的使用方法。例如,有的API要求使用預定義的回調函數,而有的API則允許使用者自己定義回調函數。

          下面就是向Flickr Search請求JSONP響應的URL,其中使用了預定義的回調函數jsonFlickrApi(參數中不必給出):

          http://api.flickr.com/services/rest/
          ?method=flickr.photos.search
          &api_key=85618ad7d326d8ef93c6bee9ed32706f
          &per_page=5&format=json&text=china

          下面這個URL發送到Google Base,它允許開發人員使用自己定義的回調函數:

          http://www.google.com/base/feeds/snippets
          ?q=jquery
          &alt=json-in-script
          &callback=customCallback

          把前面的URL放到瀏覽器地址欄中,回車,即可看到結果。



          posted on 2009-03-24 21:34 二胡 閱讀(540) 評論(0)  編輯  收藏 所屬分類: JSweb系統開發
          主站蜘蛛池模板: 宁武县| 营口市| 阳信县| 隆安县| 波密县| 二连浩特市| 湖南省| 汉寿县| 旌德县| 崇州市| 从江县| 东源县| 东丰县| 湟中县| 民权县| 巨鹿县| 玉溪市| 大厂| 四会市| 宁陕县| 建瓯市| 六盘水市| 奉新县| 石渠县| 饶河县| 太康县| 普兰县| 噶尔县| 色达县| 临夏市| 佛坪县| 饶阳县| 锦州市| 大丰市| 将乐县| 二连浩特市| 南靖县| 博客| 普安县| 屏南县| 通州区|