注:文中代码均来自 方应杭github
实现
//前端jasonp实现
function jsonp(url) {
return new Promise((resolve, reject) => {
const random = "frankJSONPCallbackName" + Math.random();
window[random] = data => {
resolve(data);
};
const script = document.createElement("script");
script.src = `${url}?callback=${random}`;
script.onload = () => {
script.remove();
};
script.onerror = () => {
reject();
};
document.body.appendChild(script);
});
}
jsonp("http://qq.com:8888/friends.js").then(data => {
console.log(data);
});
//后端nodejs相关代码
else if (path === "/friends.js") {
if (request.headers["referer"].indexOf("http://frank.com:9999") === 0) {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
const string = `window['{{xxx}}']({{data}}) `
const data = fs.readFileSync("./public/friends.js").toString();
const string2 = string.replace("{{data}}", data).replace('{{xxx}}', query.callback);
response.write(string2);
response.end();
} else {
response.statusCode = 404;
response.end();
}
}
//friends.js
{
"name":1,
"sex":2
}
代码解释
- callback
(1) 前端每次发起jsonp请求随机生成一个全局函数,将函数名以 ? callback=函数名 的方式传递给后端,后端将callback参数替换到
**window[’{{xxx}}’]({{data}})**中的‘{{xxx}}’部分。将friends.js中的数据替换到{{data}}部分
(2) 前端收到响应后,将响应作为一个script脚本执行,即执行如下代码
显然,这段代码会调用之前生成的全局监听函数,并将friends.js中的数据当作参数传入。window[函数名](数据)
(3) 可以看出,前端设置的callback函数,必须通过后端的配合来调用,否则web世界没有安全可言。 - 怎么限制允许访问的源?
服务器端的如下代码限制了只有http://frank.com:9999源的请求会被允许if (request.headers["referer"].indexOf("http://frank.com:9999") === 0)
- jsonp的关键
jsonp的实现,关键在于通过动态添加script脚本,设置其src属性,发起可以绕过同源策略限制的请求 - JSONP的适用场景
在不支持CORS的设备上发起跨域请求 - JSONP的缺点
(1) 只支持GET请求
(2) 对请求状态的支持非常有限,只有响应数据,没有状态码,没有错误信息