杂谈 -JSONP 探索

用户头像
卡尔
关注
发布于: 2020 年 06 月 01 日
杂谈-JSONP探索

前言



平时工作当中,也已经很久没有用 JSONP 来跨域请求了,现重新整理一下,写出自己对 JSONP 的理解。如果写的有不对的,请各位看官评论指出,感谢。



行文时,系统环境为 macOS Mojave v10.14.5,开发工具为 vscode 1.45.1,浏览器为 Goolge Chrome 版本 81.0.4044.138

JSONP是什么

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

这是引用了百度百科对 JSONP 的定义。笔者自己的理解是, JSONP 是一种利用浏览器 script 标签的能力实现访问跨域数据的小技巧。就是利用 script 标签能访问跨域资源的能力,利用 JSON 去填充返回内容,以达到跨域的目的。

JSONP解决了什么问题

上文说到了,JSONP 解决了跨域问题。那啥是跨域呢,简单说就是发起请求的网站与被请求的网站,它俩的协议、主机、端口不是完全一样的。表现就是,跨域时,请求是不会成功的。

JSONP 到底是怎么实现的呢,笔者的理解是,基于下面三点实现的:

  1. 浏览器的 script 标签不受同源策略的限制,可以请求到其它源的资源。

  2. script 标签请求的资源拿到后,会被浏览器的 JS引擎 执行。

  3. script 请求到的资源是在 全局上下文 里执行的。

JSONP测试

接下来就写点代码测试一下,并用大白话把过程描述一下。

用koa模拟服务端,代码如下

const koa = require("koa");
const mount = require("koa-mount");
const app = new koa();
app.use(
mount("/jsonp", (ctx) => {
let callback = ctx.query.abc;
let javascriptFileText = `
console.log(1);
${callback}("这是服务端的内容");
`;
ctx.body = javascriptFileText;
})
);
app.listen(8123);



前端代码如下

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>client</title>
</head>
<body>
<script>
function handler(res) {
console.log(res)
}
window.addEventListener('load', () => {
var url = 'http://127.0.0.1:8123/jsonp?abc=handler'
var script = document.createElement('script');
script.src = url
// 把script标签塞入到文档里,就会发起请求
document.getElementsByTagName('head')[0].appendChild(script);
})
</script>
</body>
</html>



笔者认为的过程如下:

  1. 服务端接收到 /jsonp 这个路由的请求时(当然了,是get请求),就返回一段文本,内容是一个 `console.log(1)` 和一个函数调用,在这个调用里传入 "这是服务端的内容" 。对于服务端来说,这一段始终是字符串文本。

  2. 前端在把 script 标签塞入到文档后,这个 script 就开始请求,请求拿到后是 `console.log(1);handler("这是服务端的内容")` 这样的内容,然后浏览器 JS引擎 就把这段内容执行,可以对应 eval() 理解。执行的时候,是处于 全局上下文 的。所以是能拿到 handler 这个函数的。然后呢,在 handler 里就通过 res 拿到了服务端传回给前端的内容。是不是很妙?!!我第一次用的时候,真的是眼前一亮,原来可以这么玩。

  3. 我这里取名为 abc 是为了说明, JSONP 的使用不是说一定要写成 xx/xx/xx?callback=xxx 的格式的,如果你和后台同学约定好了函数名字,你甚至可以不用传callback,直接写成 xx/xx/xx 的接口请求就行了,功能是一定能实现的,只是可能你会被同事打而已。并且, handler 方法里也不一定要传 JSON 格式的内容,你也可以写成 `handler(this)` ,然后前端页面里拿到的就是 handler 函数执行上下文里的 this 变量了,同样,这样写没有任何意义,只会被打而已。也可以写成 `handler('name="服务端给的name"&age="服务端给的age"')` ,这样,通过 & 和 = 去切割获取内容,这样也很麻烦呀,所以最终大家都选择传 JSON 格式的内容,这是最方便获取内容的方式。所以就叫 JSONP 。(这样看来,是不是也可以叫 callbackP 、 STRINGP 呢??)

后语

JSONP 这种技巧,现在(2020-06-01)已经很少有听到有还在使用的。因为现代浏览器基本都支持了 CORS 标准,这可比只支持 GET 的 JSONP 强太多了。以后,笔者估计自己是不会用到 JSONP 了,这篇文章只是笔者看到有些公司在面试时,还是会问 JSONP 的内容。所以就记录一下。



发布于: 2020 年 06 月 01 日 阅读数: 28
用户头像

卡尔

关注

还未添加个人签名 2019.03.01 加入

还未添加个人简介

评论

发布
暂无评论
杂谈-JSONP探索