# 11. jsonp的原理是什么?
尽管浏览器有同源策略,但是<script>
标签的src
属性不会被同源策略所约束,可以获取任意服务器上的脚本并执行。jsonp
通过插入script
标签的方式来实现跨域,参数只能通过url
传入,仅能支持get
请求。
原理: jsonp 是用来解决跨域获取数据的一种解决方案,具体是通过动态创建 script 标签,然后通过标签的 src 属性获取 js 文件中的 js 脚本,该脚本的内容是一个函数调用,参数就是服务器返回的数据,为了处理这些返回的数据,需要事先在页面定义好回调函数,本质上使用的并不是 ajax 技术
优缺点:
jsonp 优点:
- 完美解决在测试或者开发中获取不同域下的数据, 用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。简单来说数据的格式没有发生很大变化
jsonp 缺点:
- jsonp 只支持 get 请求而不支持 post 请求, 也即是说如果想传给后台一个 json 格式的数据, 此时问题就来了, 浏览器会报一个 http 状态码 415 错误, 告诉你请求格式不正确, 这让我很蛋疼(在登录注册中需要给后台传一大串数据), 如果都用参数的形式拼接在 url 后面的话不太现实, 后台取值也会显得繁琐,
- 在登录模块中需要用到 session 来判断当前用户的登录状态, 这时候由于是跨域的原因, 前后台的取到的 session 是不一样的, 那么就不能就行 session 来判断.
- 由于 jsonp 存在安全性问题(不知 qq 空间的跨域是怎么解决的, 还是另有高招?),后来考虑到上面的一系列问题, 采用的是后台进行设置允许跨域请求(但还是存在缺陷的, 实质上还是跨域, 如上面说的 session 问题). Header set Access-Control-Allow-Origin *为了防止 XSS 攻击我们的服务器, 我们可以限制域,比如 Access-Control-Allow-Origin: http://blog.csdn.net
# 实现原理:
- Step1: 创建 callback 方法
- Step2: 插入 script 标签
- Step3: 后台接受到请求,解析前端传过去的 callback 方法,返回该方法的调用,并且数据作为参数传入该方法
- Step4: 前端执行服务端返回的方法调用
# jsonp源码实现
function jsonp({url, params, callback}) {
return new Promise((resolve, reject) => {
//创建script标签
let script = document.createElement('script');
//将回调函数挂在 window 上
window[callback] = function(data) {
resolve(data);
//代码执行后,删除插入的script标签
document.body.removeChild(script);
}
//回调函数加在请求地址上
params = {...params, callback} //wb=b&callback=show
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
# 使用:
function show(data) {
console.log(data);
}
jsonp({
url: 'http://localhost:3000/show',
params: {
//code
},
callback: 'show'
}).then(data => {
console.log(data);
});
# 服务端代码(node):
// express启动一个后台服务
let express = require('express');
let app = express();
app.get('/show', (req, res) => {
let {callback} = req.query; //获取传来的callback函数名,callback是key
res.send(`${callback}('Hello!')`);
});
app.listen(3000);