JSONP的由来
jsonp全称json with padding,填充式的json,jsonp是为跨域而生的,在早期的前端开发中,经常用该方法解决跨域问题。
JSONP如何解决跨域
Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>)
例如,我们在本地可以引用不同域名的在线的js文件,图片地址,都可以正常加载,没有跨域问题。
//引用vue
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.0/vue.js"></script>
<img src="https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/e08da34488b114bd4c665ba2fa520a31.svg" />
jsonp就是用了这类标加载资源不会发生跨域的问题,模拟发送一个请求到后端,具体流程是这样的:
- 客户端动态的创建一个
script标签,将src设置为服务地址 - 接着在
src后面拼接上一个本地的回调函数的名字,这个函数接收一个参数,就是我们要请求的数据 - 后端解析函数,调用函数,并将我们要的数据当做参数传递进去
- 请求结束后将
script标签删掉
代码实现
来实现一下,这里使用node搭建了一个简单的服务, 执行node server.js命令,即可运行该服务,监听3001端口
server.js
const http = require('http')
const url = require('url')
http.createServer((req,res) => {
//解析客户端传递的回调函数
let clientCallBack = url.parse(req.url, true).query.clientCallBack
let message = JSON.stringify({
"city": "上海",
"street": "武康路",
"code": "101"
})
res.writeHead(200, {"Content-Type":"application/json;charset=utf-8"})
//执行函数,并将参数传递进去
res.write(`${clientCallBack}(${message})`);
res.end();
}).listen(3001)
客户端代码,就是一个基本的html页面
client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsonp</title>
</head>
<body>
<div id="message">
<h1>来自服务端的数据</h1>
</div>
<script >
//要传递给后端的回调函数,接收服务的返回数据,显示到页面上
function dataCallback(message) {
let msgDom = document.getElementById('message')
let frag = document.createDocumentFragment()
for(let k in message) {
let oDiv = document.createElement('div')
oDiv.innerHTML += `
<span>${k}</span> : <span>${message[k]}</span>
`
frag.append(oDiv)
}
msgDom.append(frag)
}
//使用jsopn,模拟请求
function requestData(cb) {
//这里将函数名拼接到服务地址后面,传递给后端,函数默认的name属性就是函数名
let url = `http://localhost:3001/?clientCallBack=${cb.name}`
//动态创建script标签
let scriptTag = document.createElement('script')
scriptTag.setAttribute('src', url)
document.getElementsByTagName('head')[0].appendChild(scriptTag)
//请求完成后,删除script标签
scriptTag.onload = function (e) {
e.currentTarget.remove()
}
scriptTag.onerror = function (e) {
e.currentTarget.remove()
}
}
requestData(dataCallback)
</script>
</body>
</html>
看下效果,很轻松拿到数据
要注意的地方
JSONP仅支持get请求,不支持POST,因为src默认是get请求
<img src='' />
<script src = ''> </script>
调用时也可以传参,后端解析即可
let url = `http://localhost:3001/?clientCallBack=${cb.name}&city=上海&code=021`