之前已经大概写了一下jsonp的简单的实现方式,今天来对其进行补充和优化,首先,先来总结一下实现jsonp的步骤:
- 将不同源的服务器端请求地址写在script标签的src属性中;
- 服务器端相应的数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数的参数
- 客户端全局作用域下定义函数fn(注:要写在请求地址前)
- 在fn内对服务器端返回的数据进行处理
然后我们就要对 上一节 的代码进行扩展和完善:
首先,我们想要把第一步写死的script标签动态生成,也就是在需要其的时候,再去创建他,不需要的时候就把他删除,我们来看看如何实现:
//jsonp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--点击按钮模拟请求-->
<button id=”btn">点击发送请求</button>
<script>
function fn(){
console.log("fn被调用")
}
</script>
<!--动态生成标签的函数-->
<script>
var btn=document.getElementById("btn")
btn.onclick=function(){
//创建script标签
var script=document.createElement("script")
//设置src属性
script.src="http://localhost:3001/test"
//添加到页面中
document.body.appendChild(script)
}
</script>
</body>
</html>
让我们先来看看结果
如图,当点击后服务器返回了和之前一样的结果,说明使其动态生成成功,可是这样有会产生一个问题,让我们先来看下面这张图片:
可以看到我们在每次点击后,都会向html中添加一个请求的script标签,我们并不想这样,怎么修改呢?很简单,script标签下有一个onload事件,这个标签会在标签创建后调用,我们在其中将这个script标签删除即可,于是修改script代码为
<script>
var btn=document.getElementById("btn")
btn.onclick=function(){
//创建script标签
var script=document.createElement("script")
//设置src属性
script.src="http://localhost:3001/test"
//添加到页面中
document.body.appendChild(script)
//添加onload事件
script.onload=function(){
//删除标签
document.body.removeChild(script)
}
}
</script>
这样就不会再body中看到这个标签了。
然后再来看下一个想要优化的点,即函数名称问题,我们如果写代码时发现函数名字重复或者出错,我们就需要同时修改客户端和服务器端上相对应的函数名称,这样很麻烦,如何解决呢?
这里有一个方法即客户端将函数名传到服务器端,这样服务器端就可以直接用这个名字,我们进行以下修改:
script.src="http://localhost:3001/test?callback=fn"
即让函数名作为参数给到客户端,相应修改服务器端的代码:
app.get("/test",(req,res)=>{
let fnName=req.query.callback;//获取传递过来的参数
let fn=fnName+"()";
res.send(fn)
})
再来尝试一下:
依然返回了正确的结果,这样,我们修改的话,只需要修改客户端函数名字就可以了,而不需要顾虑服务器端,减少了错误的发生率,很好。
再接着往下看,如果我们要发送多个请求的话,是不是每一次都需要写相同的代码呢?
为了解决这个问题,我们就要去封装一个函数,暂时就将这个函数的名称定为jsonp,如何实现呢,让我们看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<!--点击按钮模拟请求-->
<button id="btn">点击发送请求</button>
<script>
// function fn() {
// console.log("fn被调用");
// }
</script>
<!--动态生成标签的函数-->
<script>
var btn = document.getElementById("btn");
btn.onclick = function() {
//创建script标签
//设置src属性
jsonp({
url:"http://localhost:3001/test",
success:function(){
console.log("success被调用")
}
})
};
function jsonp(obj) {
//创建script标签
var script = document.createElement("script");
//需要将其变成全局函数
//防止请求覆盖生成一个随机名字
var fnName="fn"+Math.random().toString().replace(".","");
window[fnName]=obj.success
//设置src属性
script.src = obj.url+"?callback="+fnName;//不需要在关心函数名称问题
//添加到页面中
document.body.appendChild(script);
script.onload = function() {
//删除标签
document.body.removeChild(script);
};
}
</script>
</body>
</html>
结果为
这样看起来是不是就舒服了很多。
这篇文章大概就说到这里,如有不足,可以再评论区留言讨论。