jsonp 原理

工作中少不了跟 ajax 打交道,本着少造轮子的思想,一般都是使用 jquery 的 ajax 接口,同域的 ajax 大家都知道是通过 xhr(XMLHttpRequest) 请求完成, 在jquery 中,jsonp 请求也是调用的 ajax 接口,只是传递的参数不同,而其实跨域的 jsonp 请求其实根本是不同的概念,jsonp根本就没有使用到 xhr 请求。

xhr 由于同源策略限制的原因,跨域是无法完成的。jsonp 请求其实是在网页中动态的创建了一个 script 请求,这样就相当于创建了一个 GET 请求,就不会受到跨域的限制,例如在域名 abc.com 向 api.abc.com 发起一个 jsonp 请求,其实是在页面中动态添加

<script src="http://api.abc.com"></script>

稍微封装下应该是这样的:

function jsonpRequest(url){
  var script = document.createElement('script');
  script.src = url;
  document.getElementsByTagName('body')[0].appendChild(script);
}

那如何传递参数,和获取服务器返回的数据呢?传递参数很好解决,直接 url 传参就行了,而获取服务器返回的数据则需要服务器作一定的处理,这里服务器需要返回的并不是 json 数据,而是一个 js 的回调方法的调用,例如 jsonCallback({code:0}), 而这个回调函数则需要我们在页面中定义。

function jsonpCallback(data){
  console.log(data.code);
}

这样,script 请求完成后会直接执行服务器返回的回调方法,也就是我们这里定义的方法。

实际上我们的页面上可能会有不止一个 jsonp 的请求,为每个单独请求定义一个回调方法可能比较麻烦,后端的同学也可能会抱怨为每个接口定义指定的调用方法很麻烦,其实我们可以把回调的方法名作为参数传递给后端,而回调方法我们也能通过随机数生成(jquery的做法)

var jsonpCallbackNum = 1;
function jsonpRequest(url, callback){
  jsonpCallbackNum ++;
  var randomCallback = 'jsonpcallback' + jsonpCallbackNum;
  window[randomCallback] = callback;
  var script = document.createElement('script');
  spliter = url.indexOf('?') !== -1 ? '&' : '?';
  script.src = url + spliter + 'jsoncallback=' + randomCallback;
  document.getElementsByTagName('body')[0].appendChild(script);
}

恩,实现起来也并不是很难,但我这写得只是 demo,实际的业务中可能还要根据需求定义上面的代码。

发表评论