Maison  >  Article  >  interface Web  >  Analyse approfondie du protocole jsonpprincipe_json

Analyse approfondie du protocole jsonpprincipe_json

WBOY
WBOYoriginal
2016-05-16 15:38:021916parcourir

Aujourd'hui, dans le processus de développement du débogage commun, nous devons obtenir des données sur tous les domaines. Parce que jquery est utilisé, bien sûr, l'utilisation de dataType:'jsonp' peut facilement résoudre le problème.
Mais comme le backend ne prenait pas en charge l'accès jsonp à l'époque, il m'a demandé plus tard lors de l'implémentation de cette fonction, quel est le format renvoyé au format jsonp ? Je savais seulement comment l'utiliser, mais je n'arrivais pas à trouver la réponse. . .

Bien que cela ait été résolu plus tard, moi qui aime résoudre les problèmes, j'ai toujours été inquiet à ce sujet. Je dois faire des recherches approfondies, alors j'ai commencé à lire les informations, et j'ai ressenti une illumination soudaine après l'avoir vue, alors j'ai commencé à lire les informations. prévu de le faire Notes à partager avec tout le monde.

La différence entre JSON et JSONP

Bien qu'il n'y ait qu'une seule lettre de différence entre JSON et JSONP, ce n'est en réalité pas du tout la même chose : JSON est un format d'échange de données et JSONP est un protocole d'interaction de données inter-domaines. Ce que vous obtenez en utilisant la méthode JSONP. est toujours Ce sont des données au format json.

Pour parler franchement, 用JSON来传数据,靠JSONP来跨域.

JSONP expliqué en détail

Nous le savons tous, 一个页面的ajax只能获取和此页面同域的数据。, donc lorsque nous avons besoin d'obtenir des données sur plusieurs domaines, nous devons utiliser la méthode JSONP pour les obtenir.

Comme le montre la figure ci-dessous, il s'agit du message d'erreur renvoyé en utilisant le format json pour obtenir des données inter-domaines :

Alors comment le résoudre ? Les chaussures pour enfants front-end qui utilisent des frameworks peuvent avoir leurs propres méthodes correspondantes, par exemple, jquery peut le résoudre en ajoutant simplement dataType设为jsonp, mais lorsque nous l'utilisons, avons-nous déjà réfléchi à la raison pour laquelle cela peut être résolu de cette façon ? Quelle est l’idée centrale ?

Ce qui suit est une explication détaillée pour vous. La première idée est d'utiliser des balises scirpt pour introduire des données inter-domaines. Entrons lentement dans le processus de jsonp depuis le début.

Guide Étape 1

Écrireb.com/b.js Contenu :

Copier le code Le code est le suivant :
alert('hello');

Puis écrivez a.com/a.html le contenu :

Copier le code Le code est le suivant :
58cdce07cddaf1c57c79da1e351a8c6b

Exécutez a.html, le résultat est évident, bonjour apparaîtra certainement.

Guide Étape 2

Modifier b.com/b.js le contenu du fichier :

Copier le code Le code est le suivant :
myFunction('hello');

Puis modifiez le a.com/a.html contenu :

<script type='text/javascript' src='http://b.com/b.js'>
<script>
function myFunction(str)
{ //定义处理数据的函数
alert(str + ' world');
}
</script>

L'exécution de a.html fera apparaître « hello world ». Il ne devrait y avoir aucun doute à ce sujet.

Guide Étape 3

Regardons à nouveau l'étape 2 ci-dessus. Le « bonjour » dans b.js correspond aux données sous le nom de domaine b.com, et il peut être exécuté et affiché dans a.com/a.html. cela a déjà été 跨域请求数据了 mis en œuvre ?

De plus, comme le src dans la balise script ne pointe pas nécessairement vers le fichier js, il peut pointer vers n'importe quelle adresse.

Donc, nous modifions le contenu de a.html à l'étape 2 ci-dessus : 76213f686a5840fdc8272e38cbc99a7d, et nous pouvons changer le b.js en b.html ou b.json, etc., et l'exécution reviendra normalement.

Étape d'orientation 4

Les données ci-dessus sont toutes statiques et codées en dur dans le fichier, elles ne peuvent donc pas répondre à nos besoins. . . Parce que nos données de requête ajax changent en temps réel, nous devons rendre les données dynamiques.

On peut laisser la table de script appeler une page (interface) dynamique pour obtenir des données dynamiques On pense ici à 回调函数.

.

Modifier a.com/a.html le contenu de la page :

<script type='text/javascript' src='http://b.com/b.aspx&#63;callback=myFunction'>
 <script>
   function myFunction(str){ //定义处理数据的函数
    alert(str + ' world');
   }
</script>

Nous avons ajouté ?callback=myFunction à l'adresse de référence src, ce qui signifie que la fonction d'affichage des données est également transmise dynamiquement.

En utilisant la méthode jsonp pour obtenir des données, un autre point important est 后端接口也要支持jsonp才行 Par exemple, le morceau de code suivant modifie les données renvoyées au format jsonp Veuillez continuer à lire : (le langage .net est utilisé comme exemple ici. )

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&#63;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(/&#63;/) &#63; "&" : "&#63;") + (s.jsonp || "callback") + "=&#63;";     
  } // 构建新的s.data,使其包含 callback=function name
  else if (!s.data || !s.data.match(jsre))    s.data = (s.data &#63; s.data + "&" : "") + (s.jsonp || "callback") + "=&#63;";
  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(/&#63;/) &#63; "&" : "&#63;") + 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 + '&#63;' + 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数据的方法。

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn