概念
jsonp(json with padding),它不属于Ajax请求,但它可以模拟Ajax请求
将json数据当做填充内容
原理
- 将不同源的服务端请求地址写在script标签的src属性当中
// 通过script向不同源的服务端发送请求
<script src="www.example.com"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
- 服务端响应数据必须是一个函数的调用,真正要发送给客户的数据需要作为函数调用的参数。
const data = 'fun({name:"张三",age:"20"})'
res.send(data)
- 在客户端全局作用域定义函数fun 要在script之前
fun(data){}
- 在函数fun内部进行服务端返回的数据进行处理
fun(data){
console.log(data)
// 数据的处理
}
原理示例
开启2个服务器 s1 s2
s2 app.js
const express = require("express")
const path = require("path")
const app = express()
// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))
app.get("/test",(req, res)=>{
let obj = {
name:"张三",
age:18
}
res.send(`fun(${JSON.stringify(obj)})`)
})
app.listen(3001,()=>{
console.log("s2 服务器启动")
})
s1 app.js
const express = require("express")
const path = require("path")
const app = express()
// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))
app.listen(3000,()=>{
console.log("s1 服务器启动")
})
s1 public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>s1 html</title>
</head>
<body>
请求 http://localhost:3001/test
<script>
// 定义全局函数
function fun(data){
// let dat = JSON.parse(data)
console.log("dat",data)
}
</script>
<!-- 将非同源服务器端的请求地址写在script标签的src -->
<script src="http://localhost:3001/test"></script>
</body>
</html>
效果
优化示例
- 客户端要将函数名称传递到服务端
- 将 script 请求发送变成动态请求(动态添加script标签到页面)
- 封装jsonp函数
s2 app.js
const express = require("express")
const path = require("path")
const app = express()
// 开启静态资源访问
app.use(express.static(path.join(__dirname,'public')))
app.get("/test",(req, res)=>{
let obj = {
name:"张三",
age:18
}
// 接收回调函数名称
// let callback = req.query.callback
// res.send(`${callback}(${JSON.stringify(obj)})`)
// 使用方法等同于 上面的代码 回调函数的属性名 为 callback
res.jsonp(obj)
})
app.listen(3001,()=>{
console.log("s2 服务器启动")
})
s1 public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>s1 html</title>
</head>
<body>
http://localhost:3001/test
<button id="btn">发送请求 </button>
<script>
// 定义全局函数
function fun(data){
// let dat = JSON.parse(data)
console.log("dat",data)
}
let btn = document.getElementById("btn")
btn.onclick = function(){
var script = document.createElement('script');
script.src = 'http://localhost:3001/test?callback=fun'
// 把srcipt添加到页面当中 就会开始请求
document.head.appendChild(script)
script.onload = function(){ //js加载完触发
// 请求完成移除script标签
script.remove()
}
// myjsonp({
// url:'http://localhost:3001/test',
// params:{
// id:99
// },
// success:function(res){
// console.log("res",res)
// }
// })
}
</script>
</body>
</html>
封装jsonp
调用
myjsonp({
url:'http://localhost:3001/test',
params:{
id:99
},
success:function(res){
console.log("res",res)
}
})
封装
/*
* 封装jsonp
* obj
* url:请求地址
* params 参数
* success 成功回调
*/
function myjsonp(obj){
// 全局函数名称可随机生成
let fName = '_myjsonp_'+Date.now()
// 定义全局函数
window[fName] = function (data){
obj.success && obj.success(data)
}
obj.params.callback = fName
// 参数处理
let queryString = ''
Object.keys(obj.params).forEach(key=>{
queryString += key+"="+obj.params[key]+"&"
})
queryString = queryString.substring(0,queryString.length-1)
obj.url += '?'+ queryString
var script = document.createElement('script');
script.src = obj.url
// 添加到页面 开始请求
document.head.appendChild(script)
script.onload = function(){ //js加载完触发 请求完成
// 请求完成移除script标签
script.remove()
}
}