Ajax请求限制
Ajax 只允许向自己的服务器发送请求。
同源政策
同源:
多个页面拥有相同的协议
、域名和端口
、否则不同源
多个页面、多个请求在同一个服务=同源
http和https是不相同的协议
同源政策的目的
同源政策是为了保证用户信息的安全
,防止恶意的网站窃取数据。最初的同源政策是指A 网站在客户端设置的 Cookie,B网站是不能访问的。
因为同源政策的限制:不允许ajax向不同源服务端发送请求、浏览器拒收
JSONP 解决同源限制问题
jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求。
步骤
1、将不同源的服务器端请求地址写在 script 标签的 src 属性中。
<script src="www.example.com"></script>
<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
2、服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
const data = 'fn({name: "张三", age: "20"})';
res.send(data);
3、在客户端全局作用域下定义函数 fn。
//将函数定义在服务器加载的前面
function fn(data) {
4、在 fn 函数内部对服务器端返回的数据进行处理。
console.log('客服端函数被调用');
console.log(data);
}
//函数必须写在不同源服务请求的script前面
jsonp优化
1、客户端需要将函数名称传递到服务器
2、将script请求的发送编程动态请求
3、封装jsonp函数,方便请求发送
4、动态创建一个script标签
5、为script标签添加src属性 给封装函数传入对象参数
6、将script标签追加到页面中
7、在script标签完成后 把标签移除
8、因为发送的函数写在外面,导致封装性不好,所以把函数写在传递的参数对象中,需要注意的是在封装时把函数挂载在window中 使它变成全局的函数,还有一点要注意的是,在多个事件调用函数时前一个事件调用的函数可能会被后面事件调用的函数覆盖 所以在给函数命名时,使用随机命名
注意:这不是ajax请求、是模拟ajax
<script type="text/javascript">
//点击提交按钮
document.getElementById('btn1').onclick = function () {
//请求非同源服务
jsonp({
url: 'http://localhost:3001/better',
success: function (data) {
console.log(123);
console.log(data);
}
})
}
document.getElementById('btn2').onclick = function () {
//请求非同源服务
jsonp({
url: 'http://localhost:3001/better',
data:{
name:'xiaoli',
age:30
},
success: function (data) {
console.log(1233333);
console.log(data);
}
})
}
//封装 jsonp 函数,方便请求发送
function jsonp(options) {
//创建script标签
var script = document.createElement('script');
//准备把参数拼接为字符串的变量
var params='';
//遍历要传递的参数
for(var attr in options.data){
//以字符串形式拼接(参数名=参数值、多个参数之间用&隔开)
params+='&'+attr+'='+options.data[attr];
//拼接好后把参数放到请求的地址后面
}
//定义一个随机函数、挂载到window下、防止重名覆盖问题
var fnName='myJsonp'+Math.random().toString().replace('.','');
//把fn放入jsonp中、然后让它变成全局对象
window[fnName] = options.success;
//为script标签添加src属性
script.src = options.url + '?callback='+fnName+params;
//将script属性添加到页面中
document.body.appendChild(script);
//标签创建完后移除
script.onload = function () {
document.body.removeChild(script);
}
}
</script>
//服务端代码优化
app.get('/better', (req, res) => {
// 接收客户端传递过来的函数的名称
//const fnName = req.query.callback;
// 将函数名称对应的函数调用代码返回给客户端
//const data = JSON.stringify({name: "张三"});
//const result = fnName + '('+ data +')';
// setTimeout(() => {
// res.send(result);
// }, 1000)
//express方法
res.jsonp({name: 'lisi', age: 20});
});
获取腾讯天气信息案例
<body>
<div class="container">
<table class="table table-striped table-hover" align="center" id="box">
</table>
</div>
</body>
<script src="/js/jsonp.js"></script>
<script src="/js/template-web.js"></script>
<script type="text/html" id="tpl">
<tr>
<!-- 创建天气模板、遍历天气数据 -->
<th>时间</th>
<th>温度</th>
<th>天气</th>
<th>风向</th>
<th>风力</th>
</tr>
{{each info}}
<tr>
<!-- 创建天气模板、遍历天气数据 -->
<td>{{dateFormat($value.update_time)}}</td>
<td>{{$value.degree}}</td>
<td>{{$value.weather}}</td>
<td>{{$value.wind_direction}}</td>
<td>{{$value.wind_power}}</td>
</tr>
{{/each}}
</script>
<script>
//获取父元素
var box=document.querySelector('#box');
function dateFormat(data){
// console.log(data);
//截取年月日、时分秒
var year=data.substr(0,4);
var month=data.substr(4,2);
var day=data.substr(6,2);
var hour=data.substr(8,2);
var minute=data.substr(10,2);
var seconds=data.substr(12,2);
let time=year+'年'+month+'月'+day+'日'+hour+'时'+minute+'分'+seconds+'秒';
return time ;
}
//开放一个模板公共变量(必须是函数)
template.defaults.imports.dateFormat=dateFormat;
//向非同源服务器获取天气信息
jsonp({
url: 'https://wis.qq.com/weather/common',
data: {
source: 'pc',
weather_type: 'forecast_1h',
//多个数据调用
// weather_type:'forecast_1h|forecast_24h',
province: 'xx省',
city: 'xx市'
},
success: function (data) {
//模板拼接
var html=template('tpl', { info: data.data.forecast_1h });
console.log(html);
box.innerHTML=html;
}
})
</script>
CORS 跨域资源共享
CORS:全称为 Cross-originresource sharing,即跨域资源共享,
服务端做配置然后允许浏览器向跨域服务器发送 Ajax 请求
请求过程
如果是跨域、客户端请求是会携带origin、服务端请求头配置了Access-Control-Allow-Origin的话就允许通过同源限制(相当于白名单)
在服务端设置响应头
// 1.允许哪些客户端访问我
// * 代表允许所有的客户端访问我
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
// 2.允许客户端使用哪些请求方法访问我
res.header('Access-Control-Allow-Methods', 'get,post')
//一般都设置在拦截所有请求的响应代码中 记得调用next方法向下传递
同源政策是浏览器对ajax技术的限制、服务端不存在同源限制
跨服务响应数据
a页面访问a服务、a服务访问b服务、然后在响应回a页面、
下载request第三方模块、使用返回的request方法
app.get('/server', (req, res) => {
//a服务访问b服务
request('http://localhost:3001/cross', (err, response, body) => {
res.send(body);
})
});
cookie
客户端请求时,服务器响应 并且给客户端一个唯一的标识
在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息
withCredentials://指定在涉及到跨域请求时,是否携带cookie信息 默认为false–客户端
Access-Control-Allow-Credentials: true//允许客户端发送请求时携带cookie --服务器端
// 当发送跨域请求时携带cookie信息
xhr.withCredentials=true;
// 允许客户端发送跨域请求时携带cookie信息
res.header('Access-Control-Allow-Credentials', true);
这两个设置要同时设置 否则不会成功携带cookies