首先说一下什么是跨域:
跨域就是在客户端在访问服务器的时候,出现了协议、域名、端口有一项或者几项不同,就会导致跨域。也就是说,在这种情况下,跨域会阻止你的访问。向服务器发送请求后,也自然不会收到服务器返回的数据了。
那么:跨域应该如何解决呢,通常跨域有两种解决办法,一种是利用JSONP来实现跨域,另外就是使用CORS来实现跨域。
JSONP(JSON with Padding)实现跨域
原理:jsonp实现跨域的原理,就是利用script标签可以实现跨域访问,我们在使用script标签的时候,有时会直接引用外部资源,那么为何能够直接访问呢。原因就是script自带跨域啊。所以利用script标签里面的src属性就可以实现跨域访问,但是jsonp跨域只能用于get请求,这当然也是由于script使用的也是get请求了。
做法:
首先我们使用express来搭建一个小服务器用来演示。
const express = require('express');
const app = express();
app.get('/person', (req, res) => {
// 接收请求参数里面的函数名称
// 这里需要保证客户端和服务端的函数名称一致
// 函数声明在客户端,服务端来调用,并且传参。
var fnName = req.query.callback;
// 客户端将数据返回给服务端
res.send(fnName + '({name:"paul",age:23})');
});
app.listen(8001, function () {
console.log('服务器已经启动成功');
});
客户端:
<!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>
</head>
<body>
<div id="app">
<button>点我发送请求</button>
<div id="box"></div>
</div>
<script>
// 函数声明
function fn(data) {
console.log('我已经收到了数据');
console.log(data);
}
const btn = document.querySelector('button');
const box = document.getElementById('box');
btn.addEventListener('click', () => {
// 创建script标签
const script = document.createElement('script');
// 将script标签的src属性设置为要访问的地址
// 函数名称通过请求参数传给服务端
script.src = 'http://localhost:8001/person?callback=fn';
// 在页面中插入标签
box.appendChild(script);
// 访问完成移除标签
script.onload = function () {
box.removeChild(script);
};
});
</script>
</body>
</html>
在执行过程中插入script标签,并且完成请求,接收到数据后再移除script标签。
执行结果:
封装:
这里我们对jsonp的操作进行简单封装。
// 封装jsonp
function jsonp(options) {
// 传递参数,需要拼接在请求地址后面
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// 生成一个随机名字,确保每次定义的函数不重名。以防发生数据覆盖。
var fnName =
'jsonp' + Math.random().toString().replace('.', '');
// 将success函数传给window.fn(),fn()就是success别名当调用了fn就会调用
//success
// 也就是将success变成全局函数,同时还有名字
window[fnName] = options.success;
const script = document.createElement('script');
script.src = options.url + '?callback=' + fnName + params;
document.body.appendChild(script);
script.onload = function () {
document.body.removeChild(script);
};
}
// 调用封装的jsonp
btn.addEventListener('click', function () {
jsonp({
url: 'http://localhost:8001/person',
data: {
address: 'xian',
},
success: function (data) {
console.log(data);
},
});
});
对jsonp的封装方便了我们的使用
服务端可以直接使用jsonp方法
app.get('/person', (req, res) => {
// 接收请求参数里面的函数名称
// 这里需要保证客户端和服务端的函数名称一致
// 函数声明在客户端,服务端来调用,并且传参。
// var fnName = req.query.callback;
// 客户端将数据返回给服务端
// res.send(fnName + '({name:"paul",age:23})');
res.jsonp({name:'paul',age:25})
});
结果