一、同源政策
1.什么是同源
如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不同,就是不同源
2.同源政策的目的
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie,B网站是不能访问的
随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果请求,浏览器就会报错。
二、使用JSONP解决同源限制问题
1.什么是JSONP
JSONP是json with padding的缩写,它不属于ajax请求,但是它可以模拟ajax请求 ,是一个非官方的跨域解决方案,且只支持get请求
2.JSOPN怎么工作的
有一些网页的标签具体有跨域能力,例如:img、link、iframe、script
JSOPN就是利用script的跨域能力来发送请求
3.JSONP的使用
(1)将不同源的服务器端请求地址写在script标签的src属性中
<script src="www.example.com"></script>
(2)服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
(3)在客户端全局作用域下定义函数fn
function fn (data){}
将函数定义放在script标签前面,且定义在全局作用域中
(4)在fn函数内部对服务器返回的数据进行处理
三、JSOPN代码优化
1.将script发送请求变为动态请求
<body>
<button>点击发送请求</button>
<script>
function fn(data){
console.log('客户端函数被调用');
console.log(JSON.stringify(data));
}
</script>
<!-- 将非同源服务器端的请求地址写在script的src属性中 -->
<script>
const btn = document.querySelector('button');
btn.onclick = function(){
const script = document.createElement('script');
script.src = 'http://localhost:3000/server2';
document.body.appendChild(script);
//避免重复发送
script.onload = function(){
document.body.removeChild(script);
}
}
</script>
</body>
2.客户端需要将函数名称传递到服务器端
以免客户端修改函数名字影响服务器端去反复修改
<button>点击发送请求</button>
<script>
function fn(data){
console.log('客户端函数被调用');
console.log(JSON.stringify(data));
}
</script>
<script src="http://localhost:3000/server2_1?callback=fn"></script>
app.get('/server2_1',(req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
const fnName = req.query.callback;
const result = fnName + '({name:"张宇灿"})';
res.send(result);
})
3.封装jsonp函数,方便发送请求
jsonp.js
function jsonp(options){
//动态创建script标签
const script = document.createElement('script');
//为script添加src属性
script.src = options.url;
//将script追加到页面中
document.body.appendChild(script);
//当jsonp加载完成后删除script标签
script.onload = () =>{
document.body.removeChild(script);
}
}
<button>点击发送请求</button>
<script src="../../jsonp.js"></script>
<script>
function fn(data){
console.log('客户端函数被调用');
console.log(JSON.stringify(data));
}
</script>
<script>
const btn = document.querySelector('button');
btn.onclick = function(){
jsonp({
url:'http://localhost:3000/server2_1?callback=fn'
})
}
</script>
4.函数与封装的jsonp函数关联、函数
jsonp中成功/失败时调用函数已经不是全局函数
生成随机的函数名字,防止多次调用jsonp函数时,后边的覆盖前边的
function jsonp(options){
//动态创建script标签
const script = document.createElement('script');
//jsonp中成功/失败时调用函数已经不是全局函数
//随机的函数名字,防止多次调用jsonp函数时,后边的覆盖前边的
const fnName = 'myJsonp' + Math.random().toString().replace('.','');
window[fnName] = options.success;
//为script添加src属性
script.src = options.url + '?callback=' + fnName;
//将script追加到页面中
document.body.appendChild(script);
//当jsonp加载完成后删除script标签
script.onload = () =>{
document.body.removeChild(script);
}
}
5.将请求参数拼接到请求地址的后边
//拼接请求参数到地址后边
var params = '';
for(var attr in options.data){
params += '&' + attr + '=' + options.data[attr];
}
script.src = options.url + '?callback=' + fnName + params;