Rumah  >  Artikel  >  hujung hadapan web  >  Analisis mendalam tentang jsonp protocol principle_json

Analisis mendalam tentang jsonp protocol principle_json

WBOY
WBOYasal
2016-05-16 15:38:021916semak imbas

Hari ini, dalam proses membangunkan penyahpepijatan bersama, kita perlu mendapatkan data merentas domain Kerana jquery digunakan, sudah tentu, menggunakan dataType:'jsonp' boleh menyelesaikan masalah dengan mudah.
Tetapi kerana bahagian belakang tidak menyokong akses jsonp pada masa itu, dia kemudian bertanya kepada saya apabila melaksanakan fungsi ini, apakah format yang dikembalikan dalam format jsonp? Saya hanya tahu cara menggunakannya, tetapi saya tidak dapat mengetahui jawapannya. . .

Walaupun selesai kemudian, saya yang suka menyelesaikan masalah, sentiasa bimbang tentangnya, saya mesti menelitinya dengan teliti, jadi saya mula membaca maklumat itu, dan saya merasakan pencerahan yang tiba-tiba selepas melihatnya, jadi saya. merancang untuk melakukannya Nota untuk dikongsi dengan semua orang.

Perbezaan antara JSON dan JSONP

Walaupun hanya terdapat satu perbezaan huruf antara JSON dan JSONP, mereka sebenarnya bukan perkara yang sama: JSON ialah format pertukaran data dan JSONP ialah protokol interaksi data merentas domain Perkara yang anda perolehi menggunakan kaedah JSONP masih Ia adalah data dalam format json.

Secara terus terang, 用JSON来传数据,靠JSONP来跨域.

JSONP menerangkan secara terperinci

Kita semua tahu, 一个页面的ajax只能获取和此页面同域的数据。, jadi apabila kita perlu mendapatkan data merentas domain, kita perlu menggunakan kaedah JSONP untuk mendapatkannya.

Seperti yang ditunjukkan dalam rajah di bawah, ia adalah mesej ralat yang dikembalikan dengan menggunakan format json untuk mendapatkan data merentas domain:

Jadi bagaimana untuk menyelesaikannya? Kasut kanak-kanak bahagian hadapan yang menggunakan rangka kerja mungkin mempunyai kaedah yang sepadan sebagai contoh, jquery boleh menyelesaikannya dengan hanya menambah dataType设为jsonp, tetapi apabila kita menggunakannya, pernahkah kita terfikir mengapa ia boleh diselesaikan dengan cara ini? Apakah idea utama?

Berikut ialah penjelasan terperinci untuk anda Idea pertama ialah menggunakan teg scirpt untuk memperkenalkan data merentas domain. Mari perlahan-lahan masuk ke proses jsonp dari awal.

Panduan Langkah 1

Tulisb.com/b.js Kandungan:

Salin kod Kod adalah seperti berikut:
alert('hello');

Kemudian tulis a.com/a.html kandungan:

Salin kod Kod adalah seperti berikut:
a5a72787fc39f4790c4a6f6c2370e660

Jalankan a.html, hasilnya jelas, hello pasti akan muncul.

Panduan Langkah 2

Ubah suai b.com/b.js kandungan fail:

Salin kod Kod adalah seperti berikut:
myFunction('hello');

Kemudian ubah suai kandungan a.com/a.html:

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

Menjalankan a.html akan menyebabkan 'hello world' muncul. Tidak perlu ada keraguan tentang ini.

Panduan Langkah 3

Mari kita lihat langkah 2 di atas sekali lagi 'hello' dalam b.js ialah data di bawah nama domain b.com, dan ia boleh dilaksanakan dan dipaparkan dalam a.com/a.html ini sudah Sudahkah 跨域请求数据了 dilaksanakan?

Selain itu, kerana src dalam teg skrip tidak semestinya menghala ke fail js, ia boleh menunjuk ke mana-mana alamat.

Jadi, kami menukar kandungan a.html dalam langkah 2 di atas: 76213f686a5840fdc8272e38cbc99a7d, dan kami boleh menukar b.js kepada b.html atau b.json, dsb., dan pelaksanaan akan kembali seperti biasa.

Langkah Bimbingan 4

Data di atas semuanya statik dan berkod keras dalam fail, jadi ia tidak dapat memenuhi keperluan kami. . . Oleh kerana data permintaan ajax kami berubah dalam masa nyata, kami perlu menjadikan data dinamik.

Kita boleh membiarkan jadual skrip memanggil halaman dinamik (antara muka) untuk mendapatkan data dinamik Di sini kita memikirkan 回调函数.

Edit a.com/a.html kandungan halaman:

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

Kami menambah ?callback=myFunction pada alamat rujukan src, yang bermaksud bahawa fungsi untuk memaparkan data juga dihantar secara dinamik.

Menggunakan kaedah jsonp untuk mendapatkan data, satu lagi perkara penting ialah 后端接口也要支持jsonp才行 Sebagai contoh, sekeping kod berikut menukar data yang dikembalikan ke dalam format jsonp. Sila teruskan membaca: (bahasa.net digunakan sebagai contoh di sini )

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数据的方法。

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn