Jsonp(JSON with Padding) 是 json 的一种"使用模式",可让网页从别的域名(网站)获取资料,即跨域读取数据。
复制代码
Jsonp 的实现原理是经过动态建立一个 script 标签来实现的。
复制代码
跨域是由于同源策略引发的,同源指的是:协议、域名、端口号。
复制代码
example | 描述 | 是否容许跨域 |
---|---|---|
h ttp://www.a.com/a.js h ttps://www.a.com/b.js |
协议不同 | 否 |
h ttp://www.a.com/a.js h ttp://www.b.com/b.js |
域名不同 | 否 |
h ttp://www.a.com/a.js h ttp://www.a.com:8080/b.js |
端口不同 | 否 |
h ttp://www.a.com/a.js h ttp://www.192.1.1.168.com/b.js |
域名跟域名对应的IP同样 | 否 |
h ttp://www.a.com/a.js h ttp://bb.a.com/b.js |
主域名跟二级域名 | 否 |
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,所以拦截的是客户端发出的请求回来的数据接收,即请求发送了,。javascript
客户端:index.htmlhtml
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="xhr">xhr</button>
<button id="jsonp">jsonp</button>
<script> const XHR_BUTTON = document.querySelector('#xhr') XHR_BUTTON.onclick = () => { myXhr('GET', 'http://localhost:3000/test?type=1', (body) => { console.log(body) }) } function myXhr(method, url, callback) { const XHR = new XMLHttpRequest() XHR.onreadystatechange = () => { console.log(XHR.readyState, XHR.status) if (XHR.status === 200 && XHR.readyState === 4) { console.log(XHR.responseText) } } XHR.open(method, url, true) XHR.send() } </script>
</body>
</html>
复制代码
服务端: server.js前端
const http = require('http')
const url = require('url')
let source = [
{
type: 1,
value: '标题一'
},
{
type: 2,
value: '标题二'
}
]
// 开启一个服务
const app = http.createServer((req, res) => {
let pathName = url.parse(req.url).pathname;
if (pathName === '/favicon.ico') { // 排除 favicon.ico 的请求
res.end()
return
}
let queryArr = url.parse(req.url).query.split('&') // 获取路由参数
let query = {}
queryArr.forEach(item => {
let itemArr = item.split('=')
query[itemArr[0]] = itemArr[1]
})
let body = source.filter(item => item.type === +query.type)
// 响应数据
setTimeout(() => {
const BODY = JSON.stringify(body)
const JSONP_NAME = query.jsonpName
res.setHeader("Content-type","application/json"); // 解决乱码问题
if (JSONP_NAME) {
res.write(`${ JSONP_NAME }(${ BODY })`)
} else {
res.write(BODY)
}
res.end()
}, 1000)
})
// 监听 3000 端口
app.listen(3000, () => {
console.log('3000端口已被开启')
})
复制代码
服务端成功返回: java
客户端:node
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="jsonp">jsonp</button>
<script> const JSON_BUTTON = document.querySelector('#jsonp') JSON_BUTTON.onclick = () => { myJsonp('http://localhost:3000/test?type=1', 'jsonp', (body) => { console.log(body) }) } function myJsonp(url, jsonpName, callback) { if (url.includes('?')) { url += `&jsonpName=${jsonpName}` } else { url += `?jsonpName=${jsonpName}` } const script = document.createElement('script') script.src = url document.body.appendChild(script) document.body.removeChild(script) window[jsonpName] = (body) => { callback && callback(body) } } </script>
</body>
</html>
复制代码
服务端: 同上json
客户端成功拿到服务端的返回结果
复制代码
注意:后端
只支持 get 方式,不支持其它的,不够灵活跨域
【学习笔记,有错误之处敬请指教,谢谢阅读!😊】浏览器