0%

JSONP解决跨域问题

概念:

浏览器通过script标签的src属性,请求服务器上的数据,同时服务器返回一个函数的调用,这种请求数据的方式叫做JSONP

如果项目中已经配置了CORS跨域资源共享,为防止冲突,必须在配置CORS中间件之前声明JSONP的接口,否则JSONP接口会被处理成开启了CORS的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const express=require('express')
//创建web服务器
const app=express()
//导入路由模块
const apirouter=require('./apirouter')
//在配置cors中间件之前定义JSONP的接口
app.get('/api/jsonp',(req,res)=>{
//1 得到客户端请求的回调函数名称
const funcName=req.query.callback
//2 定义发送到客户端的JSON格式数据对象
const data={name:'zs',age:20}
//3 拼接一个函数调用的字符串
const scriptStr=`${funcName}(${JSON.stringify(data)})`
//4 把拼接的字符串响应给客户端的<script>标签进行解析执行
res.send(scriptStr)

})
app.use(express.urlencoded({extended:false}))
//在路由之前配置cors中间件
const cors=require('cors')
app.use(cors())

//将路由模块注册为全局中间件
app.use('/api',apirouter)
app.listen(80,()=>{
console.log('运行在http://127.0.0.1')
})

发请求:HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.staticfile.org/jquery/1.10.0/jquery.min.js">
</script>
</head>
<body>
<button id="btnJsonp">Jsonp</button>
<script>
$('#btnJsonp').on('click',function(){
$.ajax({
type:'GET',
url:'http://127.0.0.1/api/jsonp',
dataType:'jsonp',
success:function(res){
console.log(res)
}
})
})
</script>

</body>
</html>

JSONP调用是通过动态创建script元素并为src属性指定跨域URL实现的,此时script和img元素类似,能够不受限制地从其他域加载资源,因为JSONP是有效的JavaScript,所以JSONP响应在被加载完成之后会立即执行,比如以上例子中,服务器返回了带有src的script标签,客户端·收到响应后,就会去请求http://127.0.0.1/api/jsonp?callback(data)数据

缺点:

  1. JSONP是从不同域拉取可执行代码,如果这个域不可信,则可能在响应中加入恶意内容
  2. 不好确定JSONP请求是否失败,虽然HTML5规定了script元素的onerror时间处理程序,但还没有被任何浏览器实现,为此,开发者经常需要使用计时器决定是否放弃等待响应