在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
同源策略:是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
所谓同源是指" 协议+域名+端口 "三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM和JS对象无法获得
- AJAX 请求不能发送
1. JSONP :
jsonp 是 json with padding (将json 数据包裹一层 js)的缩写,它不属于Ajax 请求,但它可以模拟 Ajax 请求
1. 将不同源的服务器请求地址写在 script 标签的 src 里面
script 标签里请求地址不受同源政策的影响
注意:请求地址不是只能以 js 结尾,可以是任意形式的
2. 服务器端响应数据必须是一个函数调用,真正要发送给客户端的数据需要作为函数调用的参数
3. 在客户端提前准备好函数的定义,函数必须定义在全局作用域下,放在script 标签的前面
4. 在客户端函数的内部对客户端返回的数据进行处理
1. 客户端:
2. 服务器端:
优化:动态创建script 标签:
优化:
封装函数:
使用res里面的 jsonp 方法:
CORS:
jsonp 只支持 get;
HTTP回应中,除了关键的是Access-Control-Allow-Origin字段,其他CORS相关字段如下
1. Access-Control-Allow-Methods:必选
它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
2. Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
3. Access-Control-Allow-Credentials:可选
该字段与简单请求时的含义相同。
4. Access-Control-Max-Age:可选
node代码:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
/*
* 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
*/
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly的作用是让js无法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
反向代理:nginx
前端不直接访问,而是通过代理访问,nginx代理和服务器之间属于是服务器之间的访问,因为不存在同源限制;
nginx代理跨域,实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。
nginx 代码:
#proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}