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,实际的业务中可能还要根据需求定义上面的代码。

上一篇

Javascript 原型链与继承