logo头像

求知若渴,虚心若愚

浏览器 - 跨域解决方案 - JSONP

JSONP

JSONP:JSON with Padding

HTML脚本元素是可以规避SOP检查的,我们可以利用这个,采用动态注入脚本的方式来解决跨域问题

基本思路

  • 网页通过添加一个<script>元素,向服务器请求JSON数据
  • 这种做法不受同源政策限制
  • 服务器收到请求后,将数据放在一个指定名字的回调函数里传回来

实现步骤

  • 首先前端先设置好回调函数,并将其作为 url 的参数。
  • 服务端接收到请求后,通过该参数获得回调函数名,并将数据放在参数中将其返回
  • 收到结果后因为是 script 标签,所以浏览器会当做是脚本进行运行,从而达到跨域获取数据的目的

后端实现逻辑(Nodejs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//server.js
const url = require('url');

require('http').createServer((req, res) => {

const data = {
name: 'xiaofengge'
};
// url.parse:解析一个 URL 字符串并返回一个 URL 对象
// query.callback:获得callback对应的方法名
const callback = url.parse(req.url, true).query.callback;
res.writeHead(200);
// 返回一个函数的调用
// 这里是:jsonpCallback({name:"xiaofengge"})
// jsonpCallback是获取到的前端传递的方法名
res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, '127.0.0.1');

console.log('启动服务,监听 127.0.0.1:3000');

前端逻辑实现(html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsonp模拟</title>
</head>
<body>
<script>
function jsonpCallback(data) {
alert('获得 name 是:' + data.name);
}
</script>
<script src="http://127.0.0.1:3000?callback=jsonpCallback"></script>
</body>
</html>

TIP
后端返回的是 jsonpCallback({name:”xiaofengge”})
等同于<script>jsonpCallback({name:"xiaofengge"})</script>

JSONP优点

  • 它不像XMLHttpRequest 对象实现 Ajax 请求那样受到同源策略的限制
  • 它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
  • 在请求完毕后可以通过调用 callback 的方式回传结果,将回调方法的权限给了调用方

JSONP缺点(局限性)

  • 它支持 GET 请求而不支持 POST 等其它类行的 HTTP 请求
    • 意味着GET请求的诸多限制JSONP也有
  • 它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面或 iframe 之间进行数据通信的问题

  • jsonp在调用失败的时候不会返回各种HTTP状态码

    • 如果脚本注入成功后,就会调用回调函数,但是注入失败后,没有任何提示
    • 这就意味着,当JSONP遇到404、505或者其他服务器错误时,你是无法检测出错原因的
    • 我们能够做的也只有超时,没有收到响应,便认为请求失败,执行对应的错误回调
  • 借助JSONP有可能进行跨站请求伪造(CSRF)攻击

TIP
当一个恶意网站使用访问者的浏览器向服务器发送请求并进行数据变更时,被称为CSRF攻击。
由于请求会携带cookie信息,服务器会认为是用户自己想要提交表单或者发送请求,而得到用户的一些隐私数据

支付宝打赏 微信打赏

赞赏是对我们的肯定!