Ajax请求限制
Ajax只能向自己的服务器发送请求
同源政策
同源:
来自同一个地方(服务器端)
如果两个页面又有相同的协议、域名和端口,name这两个页面就属于同一个源,只要有一个不相同,就是不同源
示例
http://www.example.com
http://example.com
http://v2.www.example.com
这三个网站的域名不同 属于不同源
http和https是不相同的协议
同源政策的目的
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie,B网站是 不能访问的
Ajax请求是不能向非同源服务器发送请求的
使用JSONP解决同源限制问题
json with padding 不属于Ajax请求,但是可以模拟Ajax请求,需要前后端配合完成
script
标签不受同源政策的影响
步骤
- 将不同源的服务器请求地址写在script标签的src属性中
<script src="www.example.com"></script>
- 服务器端响应数据必须是一个函数调用的代码,真正要发送给客户端的数据需要作为函数调用的参数 里面的代码要符合JavaScript的规则,因为在请求完成后,会去执行里面的代码
const data="fn({name:'zhangsan',age:'20'})"//传入实参 res.send(data);
- 要在客户端提前准备好函数 即在客户端全局作用域下定义函数fn
function fn(data){}
必须将定义写在请求的script前面 - 在fn函数内部对服务器端返回的数据进行处理
function fn(data){}
JSONP 代码优化
客户端需要将函数名称传递到服务器端
就是客户端定义的函数名称传入到服务器端 服务器调用在返回 减少需要修改函数名的情况
get方式就是直接将函数名传入地址栏中的参数中
例如
http://www.example.com?callback=fn
封装JSONP
- 客户端需要将函数名称传递到服务器
- 将script请求的发送编程动态请求
- 封装jsonp函数,方便请求发送
- 动态创建一个script标签
- 为script标签添加src属性 给封装函数传入对象参数
- 将script标签追加到页面中
- 在script标签完成后 把标签删除
- 因为发送的函数写在外面,导致封装性不好,所以把函数写在 传递的参数对象中,需要注意的是在封装时把函数挂载在window中 使它变成全局的函数,还有一点要注意的是,在多个事件调用函数时前一个事件调用的函数可能会被后面事件调用的函数覆盖 所以在给函数命名时,使用随机命名
最终代码
<!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>
<input type="button" value="1" id='btn1'>
<input type="button" value="2" id='btn2'>
<script>
function JSONP(options) {
//动态创建一个script标签
var script = document.createElement('script');
//获取参数,拼接字符串
var params = '';
for (var key in options.data) {
params += '&' + key + '=' + options.data[key];
}
//防止函数重名被覆盖 需要随机命名函数
var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
//获取需要执行的函数 将其挂载在全局下
// window.fn = options.success;
window[fnName] = options.success;
//为标签添加src属性
script.src = options.url + '?callback=' + fnName + params;
//将标签添加到页面中
document.body.appendChild(script);
//在该标签完成事情后 删除该标签
script.onload = function () {
document.body.removeChild(this);
}
}
</script>
<script>
document.getElementById('btn1').onclick = function () {
var testObj = {
url: 'http://localhost:3001/better',
data: {
name: 'lsie',
age: 25
},
success: function (data) {
console.log('封装的函数被调用了1');
console.log(data);
}
}
JSONP(testObj);
}
document.getElementById('btn2').onclick = function () {
var testObj2 = {
url: 'http://localhost:3001/better',
success: function (data) {
console.log('封装的函数被调用了2');
console.log(data);
}
}
JSONP(testObj2);
}
</script>
</body>
</html>
CORS跨域资源共享
Cross-origin resource sharing
允许浏览器向跨域服务器发送Ajax请求
服务器端允许就能跨域 不允许就不能跨域 主要是在服务器端做一些配置 客户端ajax不变
请求过程
浏览器检测到是跨域 就会发送请求字段origin
中存储的地址
如果服务器端同意该请求 就会在响应有中加入Access-Control-Access-Origin
字段–>存储的是当前访问服务器端的客户端的原信息或者是(允许所有的服务器端访问该客户端)
在服务器端中设置响应头
res.header('Access-Control-Access-Origin','服务器端地址');
//允许客户端使用那些请求方式访问
res.header('Access-Control-Access-Origin','get,post');
一般都设置在拦截所有请求的响应代码中 记得调用next
方法
服务器端解决方案
同源政策是浏览器给予Ajax技术的限制,服务器端不存在同源政策限制的
可以让服务器端去获取非同源服务器端的数据,在把数据获取到的数据响应到自己的客户端中
使用request第三方模块
访问不同服务器端的数据
request('请求地址',function(err,response,body){
err-->错误信息
response-->服务器端的响应信息
body-->服务器端返回的信息
})
cookie
服务器请求时,客户端响应 并且给服务器一个唯一的标识
在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息
withCredentials
属性–客户端
指定在涉及到跨域请求时,是否携带cookie信息 默认为false
Access-Control-Allow-Credentials
: true允许客户端发送请求时携带cookie --服务器端
这两个设置要同时设置 否则不会成功携带cookies