json和jsonp縮寫只相差一個字母,可是二者卻徹底不一樣。前者是一種數據的表達方式,後者則是網絡請求的一種解決方案。javascript
使用ajax發送網絡請求有一個條件,那就是同源策略。php
同源策略要求:java
http
、https
、ftp
等等https://www.baidu.com/
或者本身的主機ip地址8080
、80
等等例如日常使用webstorm進行調試的時候,webstorm會開一個本地服務器http://localhost:63342/xxxx
,可是若是你使用ajax去訪問https://www.baidu.com/
之類的服務器你是沒法拿到數據的。實際上瀏覽器已經拿到數據,可是作了一層隔離,不給你數據。node
在說原理以前首先要了解兩個關於<script>
的特色web
<script>
標籤可使用cdn加速(根據瀏覽器所在網絡地區,從最近的服務器下載js腳本,通常下載框架和庫),那麼cdn的服務器毫無疑問是不一樣源的。因此,<script>
標籤能夠跨域訪問別的服務器。<script>
標籤是經過src
節點屬性獲取js代碼的,而且獲取到的代碼能夠直接執行。在瞭解了上面的2個<script>
的特色以後大概都能猜出來,jsonp就是使用<script>
以上兩個特色來實現的,具體的實現方式有2種。ajax
方式一編程
<script>
標籤發送請求,拼接上callback=方法名
參數。callback
參數,拿到方法名後在方法名後拼接()
,而且傳入返回的數據這種方式對於php來講就是字符串拼接,可是傳回來的時候則是被js解析成調用對應的方法了。json
// php $res = file_get_contents($url); $func = $_GET[callback]; echo callback.'('.$res.')';
方式二後端
jsonp不管如何都要後端支持(要麼是本身的後端寫的php,要麼是別人接口支持jsonp跨域的回調方法),不然沒法使用。api
// 1. 建立一個script標籤 var script = document.createElement('script'); // 2. 隨機生成一個方法 // 用時間戳做爲種子,這樣隨機生成的方法名絕對沒有重複的。 var funcName = 'jsonpFunc' + Math.floor(new Date().getTime() * Math.random()); window[funcName] = function (json) { console.log(json); // 把請求完的標籤從文檔中移除 document.head.removeChild(script); }; // 3. 拼接請求地址,加上回調 script.src = 'http://api.douban.com/v2/movie/in_theaters?callback=' + funcName; // 4. 把script標籤放到文檔中,就會發送請求 document.head.appendChild(script);
封裝一下:
window.myJsonp = function (opt) { // 簡單的容錯 if (!opt || !opt.url) return; opt.callback = opt.callback || 'callback'; opt.params = opt.params || {}; opt.callback = opt.callback || function () {}; // 1. 建立一個script標籤 var script = document.createElement('script'); // 2. 隨機生成一個方法 var funcName = 'jsonpFunc' + Math.floor(new Date().getTime() * Math.random()); window[funcName] = function (json) { // 5. 把請求完的標籤從文檔中移除 document.head.removeChild(script); // 6. 刪除添加到window的方法名稱,避免污染 delete window[funcName]; // 7. 把獲取到的數據經過回調的方式傳出去 opt.callback(json); }; // 3. 拼接請求地址,加上回調(參數拼接和get請求一致) var params = ''; for (var key in opt.params) { params += key + '=' + opt.params[key] + '&'; } script.src = opt.url + '?' + params + 'callback=' + funcName; // 4. 把script標籤放到文檔中,就會發送請求 document.head.appendChild(script); }; // 使用 myJsonp({ url: 'http://api.douban.com/v2/movie/in_theaters', callback: function (json) { console.log(json); } });
待續。。。