亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入分析jsonp協議原理

2019-11-20 11:31:04
字體:
來源:轉載
供稿:網友

今天在開發聯調的過程中,需要跨域的獲取數據,因為使用的jquery,當然使用dataType:'jsonp'就能夠很easy的解決了。
但是因為當時后端沒有支持jsonp來訪問,后來他在實現這個功能的時候問了我一句,jsonp形式返回的格式是怎么樣子的?我一直以來只知道怎么使用,迷迷糊糊的卻沒有答上來。。。

雖然后來解決了,但是對于喜歡解決問題的我,心里卻一直耿耿于懷,必須得把這個研究透徹了,于是我開始翻閱資料,看到后面真有種豁然開朗的感覺,于是打算做個筆記與大家分享。

JSON和JSONP的區別

JSON和JSONP雖然只有一個字母的差別,但其實他們根本不是一回事兒:JSON是一種數據交換格式,而JSONP是一種跨域數據交互的協議,使用JSONP方法獲取到的仍然是json格式的數據。

說白了,用JSON來傳數據,靠JSONP來跨域。

JSONP詳細闡述

我們都知道,一個頁面的ajax只能獲取和此頁面同域的數據。,所以當我們需要跨域獲取數據的時候就需要使用到JSONP方法來獲取了。

如下圖所示,就是使用json格式獲取跨域數據返回的錯誤提示:

那么該如何解決呢?使用框架的前端童鞋們可能都有自己相應的辦法,比如jquery就是把dataType設為jsonp就能解決了,但是我們在使用的時候有沒有想過,為什么這樣就能解決呢?中心思想又是什么呢?

下面就開始為大家詳細闡述,首要思想就是利用scirpt標簽來引入跨域的數據。我們從最開始慢慢來深入jsonp的過程。

引導步驟1

編寫b.com/b.js內容:

復制代碼 代碼如下:
alert(‘hello');

然后編寫a.com/a.html內容:

復制代碼 代碼如下:
<script type='text/javascript' src='http://b.com/b.js'>

運行a.html,結果很明顯,肯定會彈出hello。

引導步驟2

修改b.com/b.js文件內容:

復制代碼 代碼如下:
myFunction('hello');

然后修改a.com/a.html內容:

<script type='text/javascript' src='http://b.com/b.js'><script>function myFunction(str){ //定義處理數據的函數alert(str + ' world');}</script>

運行a.html 結果是彈出‘hello world'。這個應該也毫無疑問。

引導步驟3

讓我們再看一下上面的步驟2,b.js中的‘hello'就是b.com域名下的數據了,而能夠在a.com/a.html中執行顯示出來,這不就已經實現了跨域請求數據了嗎?

另外,因為script標簽中的src 不一定要指向js文件,而可以指向任何地址。

所以,我們把上面步驟2中a.html的內容:<script type='text/javascript' src='http://b.com/b.js'>,我們把其中的b.js改成b.html或者b.json等等都是可以的,執行都能正常返回。

引導步驟4

上面的數據都是靜態的,是在文件內寫死的,所以并不能滿足我們的需求了吧。。。因為我們ajax請求數據是實時變化的,所以我們要把數據變成動態的了。

我們可以讓script表器去調用一個動態的頁面(接口),去實現獲取動態數據,這里就想到了回調函數.

編輯a.com/a.html頁面內容:

<script type='text/javascript' src='http://b.com/b.aspx?callback=myFunction'> <script>   function myFunction(str){ //定義處理數據的函數    alert(str + ' world');   }</script>

我們在src引用地址中加了?callback=myFunction,意思是把顯示數據的函數也動態的傳入了。

使用jsonp方法獲取數據,還有一個要點就是后端接口也要支持jsonp才行,比如下面一段代碼就是讓返回的數據變成jsonp的格式,請繼續看:(此處使用.net語言作為例子)

protected void page_load(object sender, EventArgs e){  if(this.IsPostBack == false){    string callback = '';    if(Request["callback"] != null){      callback = request["callback"];      string data = "hello";      Response.Write(callback+"("+ data + ")"); //接口頁面返回的數據格式“函數(參數)”的格式。    }  }}

代碼的意思很簡單,就是獲取調用函數的參數。如果這里調用b.aspx?callback=myFunction的話,則會返回myFunction('hello'),如果后端代碼給data賦值一個變量,這里的‘hello'則變成了動態的數據了。

引導步驟5

再看上面的步驟,雖然獲取的數據是動態的了,但在頁面上引入一個script標簽,卻只能執行一次,獲取一次,顯然還是不能滿足需求的。所以我們在需要的時候,就得動態的添加一次這樣的script標簽。

所以我們在這里需要封裝一個函數:

function addScript(src){   var script = document.createElement('script');   script.setAttribute('type','text/javascript');   script.src= src;   document.body.appendChild(script); }

需要調用的時候,就去執行:

addScript('b.com/b.aspx?callback=myFunction');    function myFunction(data){//定義處理數據的函數     alert(data);   }

ok,上面的過程就是jsonp的原理,我們不必去記住那些令人糾結不清的定義,只要看一遍這個過程,我相信就能明白其中的精髓了吧。

jquery實現跨域

jquery跨域方法

$.ajax({  url: 'b.com/b.json', //不同的域  type: 'GET', // jsonp模式只有GET是合法的  dataType: 'jsonp', // 數據類型  jsonp: 'callback', // 指定回調函數名,與服務器端接收的一致,并回傳回來  success: function(data) {    console.log(data);  }})

使用jquery非常方便,那么它是怎么實現這個轉化的呢?下面我們來看看這部分的jquery源碼。

jq實現jsonp源碼分析

我貼出網上給的jquery實現jsonp部分的源碼分析:

if (s.dataType == "jsonp") {   // 構建jsonp請求字符集串。jsonp是跨域請求,要加上callback=?后面將會加函數名               if (type == "GET") { //使get的url包含 callback=?后面將 會進行加函數名    if (!s.url.match(jsre))      s.url += (s.url.match(/?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";       } // 構建新的s.data,使其包含 callback=function name  else if (!s.data || !s.data.match(jsre))    s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";  s.dataType = "json";}//判斷是否為jsonp,如果是 ,進行處理。if (s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre))) {    jsonp = "jsonp" + jsc ++; //為請 求字符集串的callback=加上生成回調函數名  if (s.data) s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");    s.url = s.url.replace(jsre, "=" + jsonp + "$1"); // 我們需要保證jsonp 類 型響應能正確地執行     //jsonp的類型必須為script。這樣才能執行服 務器返回的     //代碼。這里就是調用這個回調函數。  s.dataType = "script";  //window下注冊一個jsonp回調函數 有,讓ajax請求返回的代碼調用執行它,  window[jsonp] = function(tmp) {       data = tmp;    success();    complete();   // 垃圾回收,釋放聯變量,刪除jsonp的對象,除去head中加的script元素      window[jsonp] = undefined;       try {       delete window[jsonp];         } catch (e) {}       if (head)  head.removeChild(script);     };  }if (s.data && type == "GET") {    // data有效,追加到get類型的url上去  s.url += (s.url.match(/?/) ? "&" : "?") + s.data;    // 防止IE會重復發送get和post data  s.data = null;}if (s.dataType == "script"  && type == "GET" && parts && (parts[1] && parts[1] != location.protocol || parts[2] != location.host)) {    // 在head中加上<script src=""></script>  var head = document.getElementsByTagName("head")[0];     var script = document.createElement("script");     script.src = s.url;     if (s.scriptCharset) script.charset = s.scriptCharset;  if (!jsonp) {  //如果datatype不是jsonp,但是url卻是跨域 的。采用scriptr的onload或onreadystatechange事件來觸發回 調函數。    var done = false; // 對所有瀏覽器都加上處理器    script.onload = script.onreadystatechange = function() {           if (!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {                 done = true;         success();                complete();        head.removeChild(script);             }       };    }    head.appendChild(script); // 已經使用 了script 元素注射來處理所有的事情  return undefined;}

上面的代碼稍顯復雜,但是我們挑揀重要的看就好了。

我們來分析一下這個過程,其實這個過程也就是上面我提出問題的答案了:

這里執行代碼之后,其實就是判斷是否配置了dataType: 'jsonp',如果是jsonp協議,則要在url上加callback=jQueryxxx(函數名),jquery會把url轉化為:http://b.com/b.json?callback=jQueryxxx,然后再在html中插入,加載完b.json這個文件后,就會執行jQueryxxx這個回調函數,而且此時這個函數里面已經存在了動態數據(json格式數據),所以在頁面上執行的時候就能夠隨心所欲的處理數據了,但是也別忘了后端也要支持jsonp格式才行。所以這樣就達到了跨域獲取數據的功能。

原生js封裝jsonp

function jsonp(config) {    var options = config || {};  // 需要配置url, success, time, fail四個屬性    var callbackName = ('jsonp_' + Math.random()).replace(".", "");    var oHead = document.getElementsByTagName('head')[0];    var oScript = document.createElement('script');    oHead.appendChild(oScript);    window[callbackName] = function(json) { //創建jsonp回調函數      oHead.removeChild(oScript);      clearTimeout(oScript.timer);      window[callbackName] = null;      options.success && options.success(json);  //先刪除script標簽,實際上執行的是success函數    };    oScript.src = options.url + '?' + callbackName;  //發送請求    if (options.time) { //設置超時處理      oScript.timer = setTimeout(function () {        window[callbackName] = null;        oHead.removeChild(oScript);        options.fail && options.fail({ message: "超時" });      }, options.time);    }  };

這是我自己寫的一個原生js實現jsonp獲取跨域數據的方法。

我們只需要調用jsonp函數就能夠跨域獲取數據了。比如:

jsonp({    url: '/b.com/b.json',    success: function(d){      //數據處理    },    time: 5000,    fail: function(){      //錯誤處理    }      })
小結

再說幾點注意的地方:

使用jsonp方法時,在控制臺的network-JS中才能找到調用的接口,不再是XHR類了。由于頁面渲染的時候script只執行一次,而且動態數據需要多次調用,所以在插入使用之后需要刪除,并且要初始化回調函數。原生js實現時,最好加一個請求超時的功能,方便調試。

總之jsonp就是一種獲取跨域json數據的方法。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久综合色88| 亚洲电影免费在线观看| 久久综合电影一区| 亚洲欧美另类人妖| 精品久久在线播放| 亚洲精品自拍视频| 久久久精品网站| 日韩中文在线中文网三级| 在线视频欧美日韩精品| 亚洲综合小说区| 亚洲男人天堂古典| 亚洲wwwav| 91精品国产综合久久男男| 日韩第一页在线| 国产a∨精品一区二区三区不卡| 亚洲人成网站999久久久综合| 欧美国产在线电影| 国产精品青草久久久久福利99| 黄色一区二区在线观看| 中文字幕日韩在线观看| 亚洲欧美国产va在线影院| 国产精品爱久久久久久久| 欧美国产亚洲精品久久久8v| 亚洲性猛交xxxxwww| 日韩精品久久久久久福利| 欧美日韩裸体免费视频| 日韩一区在线视频| 日本精品视频在线播放| 日韩在线免费av| 欧美最猛性xxxxx(亚洲精品)| 午夜精品免费视频| 亚洲一区二区自拍| 一本色道久久综合亚洲精品小说| 日韩欧美a级成人黄色| 国内精品中文字幕| 亚洲激情视频在线观看| 狠狠躁18三区二区一区| 久久久久这里只有精品| 欧美日韩激情小视频| 久久久精品电影| 亚洲人午夜精品免费| 久久精品青青大伊人av| 欧美激情国产精品| 亚洲精品久久久久久久久久久久| 91亚洲va在线va天堂va国| xvideos亚洲人网站| 亚洲18私人小影院| 亚洲精品欧美日韩| 丝袜亚洲欧美日韩综合| 狠狠躁天天躁日日躁欧美| 日韩美女在线观看一区| 久久综合88中文色鬼| 亚洲精品国产精品国自产在线| 黄色一区二区在线| 国产成人免费91av在线| 亚洲韩国欧洲国产日产av| 在线观看免费高清视频97| 国产精品欧美一区二区| 日韩最新免费不卡| 九九久久久久99精品| 97在线视频免费| 国产精品自产拍高潮在线观看| 欧美日韩国产麻豆| 国产精品香蕉国产| 亚洲欧美在线免费| 国产一区香蕉久久| 伊人男人综合视频网| 国外成人免费在线播放| 久久天天躁日日躁| 国产精品自拍视频| 国产精品国产三级国产aⅴ浪潮| 日韩av电影在线播放| 国产精品国产三级国产aⅴ9色| 成人伊人精品色xxxx视频| 国产在线视频不卡| 国内外成人免费激情在线视频| www.xxxx精品| 欧美午夜宅男影院在线观看| 欧美孕妇毛茸茸xxxx| 亚洲天堂网在线观看| 国产97在线播放| 综合国产在线视频| 黄色成人av网| 久久精品国产99国产精品澳门| 久久综合久中文字幕青草| 中文字幕欧美专区| 亚洲免费中文字幕| 欧美大荫蒂xxx| 2019亚洲日韩新视频| 国产精品久久久久久久久久久久| 亚洲欧洲一区二区三区在线观看| 日本成人免费在线| 欧美精品日韩www.p站| 国产精品综合网站| 欧美成人全部免费| 黑人极品videos精品欧美裸| 亚洲在线一区二区| 中文字幕亚洲激情| 国产原创欧美精品| 欧美成人精品在线观看| 亚洲人成网站999久久久综合| 中文字幕欧美专区| 国产69精品久久久久久| 欧美极品欧美精品欧美视频| 国产91露脸中文字幕在线| 久久亚洲精品网站| 欧美日韩国产激情| 日韩一区二区久久久| 国产午夜精品免费一区二区三区| 国产精品久久久久久久久久ktv| 亚洲一区二区中文字幕| 久久久久久国产精品| 久久免费视频这里只有精品| 国产精品久久电影观看| 欧美国产日韩一区二区三区| yw.139尤物在线精品视频| 日韩欧美国产黄色| 久久视频中文字幕| 久热精品视频在线免费观看| 亚洲91精品在线观看| 久久久久久成人精品| 91国内在线视频| 97av在线视频| 欧美成年人网站| 成人激情在线观看| 在线电影av不卡网址| 国内外成人免费激情在线视频| 国产成人精品久久| 国内成人精品视频| 日韩av在线最新| 久久精品色欧美aⅴ一区二区| 69av在线播放| 成人激情视频小说免费下载| 亚洲自拍偷拍一区| 欧美激情女人20p| 国产精品jvid在线观看蜜臀| 欧美福利视频在线| 2020久久国产精品| 日韩av电影国产| 日韩禁在线播放| 国产日本欧美一区| 亚洲精品国产精品国自产观看浪潮| 亚洲激情自拍图| 中文字幕精品网| 精品亚洲一区二区三区在线观看| 欧美一级bbbbb性bbbb喷潮片| 国产精品电影网站| 日韩中文字幕在线视频| 久久久久久久97| 亚洲精品98久久久久久中文字幕| 青青a在线精品免费观看| 国产精品丝袜视频| 亚洲精品福利在线观看| 成人免费看黄网站| 日韩av一区二区在线观看| 亚洲第一区在线观看| 欧美三级欧美成人高清www| 亚洲欧美制服第一页| 欧美精品激情视频| 亚洲成人免费在线视频| 成人黄色中文字幕| 亚洲激情在线视频| www国产精品视频| 国产精品高潮在线|