「每日一題」JSONP 是什麼?
function jsonp(setting){n //補充代碼n}njsonp({n url: http://photo.sina.cn/aj/index,n key: jsoncallback,n data: {n page: 1,n cate: recommendn },n callback: function(ret){n console.log(ret)n }n})n
背景:
小谷同學在學習 ajax 後想做一個簡單的天氣預報應用,但找不到合適的天氣介面,便向小飢求助。應小谷的要求小飢寫了一個獲取當前訪問者所在地天氣的介面發布到線上,介面URL: http://api.jirengu.com/weather.php。小谷把 URL複製到瀏覽器瀏覽器地址欄按下回車鍵,頁面很神奇地展示了小谷所在城市的天氣數據。於是小谷立即寫了個頁面,使用 ajax 調用當前介面,代碼如下:
$.get(http://api.jirengu.com/weather.php)n .then(function(ret){n console.log(ret)n})n
小谷打開控制台,滿心期待想看到返回的天氣數據,但映入眼帘的是幾行紅色的警告:
「啥 JSONP? callback? 跨域這個詞貌似聽過,我自己先查查別讓小飢那小子鄙視我」小谷暗暗的想,「原來是跨域啊,你不早說,謝啦」,回到工位小谷趕緊打開谷歌。
同源策略(Same origin Policy)
瀏覽器出於安全方面的考慮,只允許與同域下的介面交互。
同域指的是?
- 同協議:如都是http或者https
- 同域名:如都是http://jirengu.com/a 和http://jirengu.com/b
- 同埠:如都是80埠
比如: 用戶打開了 頁面: http://jirengu.com/blog, 當前頁面下的 js 向 http://jirengu.com/xxx 的介面發 ajax 請求,瀏覽器是允許的。但假如向: http://hunger-valley.com/xxx 發ajax請求則會被瀏覽器阻止掉,因為存在跨域調用。
「原來如此,怪不得瀏覽器會報錯。跨域不過如此嘛!那 JSONP是什麼呢?」
HTML 中 script 標籤可以載入其他域下的js,比如我們經常引入一個其他域下線上cdn的jQuery。那如何利用這個特性實現從其他域下獲取數據呢?
可以先這樣試試:
<script src="http://api.jirengu.com/weather.php"></script>n
這時候會向天氣介面發送請求獲取數據,獲取數據後做為 js 來執行。
但這裡有個問題, 數據是 JSON 格式的數據,直接作為 JS 運行的話我如何去得到這個數據來操作呢?
這樣試試:
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>n
這個請求到達後端後,後端會去解析callback這個參數獲取到字元串showData,在發送數據做如下處理:
之前後端返回數據: {"city": "hangzhou", "weather": "晴天"}n現在後端返回數據: showData({"city": "hangzhou", "weather": "晴天"})n
前端script標籤在載入數據後會把 「showData({"city": "hangzhou", "weather": "晴天"})」做為 js 來執行,這實際上就是調用showData這個函數,同時參數是 {"city": "hangzhou", "weather": "晴天"}。
用戶只需要在載入提前在頁面定義好showData這個全局函數,在函數內部處理參數即可。
<script>n function showData(ret){n console.log(ret);n }n</script>n<script src="http://api.jirengu.com/weather.php?callback=showData"></script>n
「原來這就是 JSONP(JSON with padding),總結一下:」
1. JSONP是通過 script 標籤載入數據的方式去獲取數據當做 JS 代碼來執行
2. 提前在頁面上聲明一個函數,函數名通過介面傳參的方式傳給後台,後台解析到函數名後在原始數據上「包裹」這個函數名,發送給前端。換句話說,JSONP 需要對應介面的後端的配合才能實現。
「原理很簡單,但用起來代碼好醜陋,我做個封裝讓小飢看看」
function jsonp(setting){n setting.data = setting.data || {}n setting.key = setting.key||callbackn setting.callback = setting.callback||function(){} n setting.data[setting.key] = __onGetData__nn window.__onGetData__ = function(data){n setting.callback (data);n }nn var script = document.createElement(script)n var query = []n for(var key in setting.data){n query.push( key + =+ encodeURIComponent(setting.data[key]) )n }n script.src = setting.url + ? + query.join(&)n document.head.appendChild(script)n document.head.removeChild(script)nn}nnjsonp({n url: http://api.jirengu.com/weather.php,n callback: function(ret){n console.log(ret)n }n})njsonp({n url: http://photo.sina.cn/aj/index,n key: jsoncallback,n data: {n page: 1,n cate: recommendn },n callback: function(ret){n console.log(ret)n }n})n
查看代碼:飢人谷JS Bin
小谷成就感爆棚,「小飢定會刮目相看的... 」
完
作者:若愚,本文為作者辛苦原創,知乎首發,轉載需私信向作者申請
快快加入前端技術交流 QQ6群:108801207。這裡有
- 嚴格的審核制度,杜絕廣告、推銷。尊重、有愛、互助,任何水平的前端愛好者都能找到歸宿
- 每日一題,每周資源推薦,精彩博客推薦,工作、筆試、面試經驗交流解答,免費直播課,群友輕分享... ,數不盡的福利免費送
推薦閱讀:
※慢時光
※引入 CSS 的方式
※前端開發者應知必會:瀏覽器是如何渲染網頁的
※「每日一題」CSRF 是什麼?
※從零學習前端開發·HTML