跨域:
不遵循同源策略的网络请求会形成跨域问题,同源策略如下:
解决方案:
一.Jsonp
原理: script标签引入js文件不受跨域影响。不仅如此,带src属性的标签都不受同源策略的影响。
基于这个特性,我们通过script标签的src属性加载资源,数据放在src属性指向的服务器上,使用json格式。
由于我们无法判断script的src的加载状态,并不知道数据有没有获取完成,所以事先会定义好处理函数。服务端会在数据开头加上这个函数名,等全部加载完毕,便会调用我们事先定义好的函数,这时函数的实参传入的就是后端返回的数据了。
应用:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function callback(data) {
alert(data.test);
}
</script>
<script src="./jsonp.js"></script>
</body>
</html>
jsonp.js
callback({"test": 0});
该方案的缺点是:只能实现get一种请求。
但是目前由于Chrome浏览器更新,无法满足第三方cookie。在跨域的过程中会出现以下错误:
A cookie associated with a cross-site resource at http://baidu.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`.
参考:http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
https://blog.csdn.net/yup1212/article/details/87633272
二.跨域资源共享(CORS)
原理:CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
应用:
要同时在前端和后端做一些设置。
对于普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
1.前端设置
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
2.服务端设置:
1)Java后台示例:
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
2.)Nodejs后台示例:
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...');
参考:
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://segmentfault.com/a/1190000011145364