同源策略
所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个IP地址,也非同源。
同源策略限制以下几种行为:
- Cookie、LoaclStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- Ajax 请求不能发送
跨域解决方案
JSONP
通常为了减轻web服务器的负载,我们把js、css、img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。 ```javascript const script = document.createElement(‘script’); script.type = ‘text/javascript’;
// 传参一个回调函数名给后端,后端返回时将参数传入并执行这个在前端定义的回调函数
<a name="KSzHH"></a>#### 跨域资源共享(CORS)普通跨域请求:服务端只需设置Access-Control-Allow-Origin即可,前端无需设置,若要带Cookie请求:前后端都需要设置。需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。<a name="4yLvX"></a>##### 前端设置原生Ajax```javascriptvar xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容// 前端设置是否带cookiexhr.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);}};
axios
axios.defaults.withCredentials = true;
node后端示例:
const http = require('http');const server = http.createServer();const qs = require('qs');server.on('request',function(req,res){let postData = '';// 数据块接收中req.addListener('data',function(chunk){postData += chunk;})// 数据接收完毕req.addListen('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'})res.write(JSON.stringify(postData));res.end();})})server.listen(3000)
nginx代理跨域
nginx配置解决iconfont跨域
浏览器跨域访问 js, css, img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态服务器中加入以下配置:
location / {add_header Access-Control-Allow-Origin *;}
nginx反向代理接口跨域
跨域原理:同源策略是浏览器的安全策略,不是Http协议的一部分。服务器端调用Http接口只是使用Http协议,不会执行JS脚本,不需要同源策略,也就不存在跨域问题。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中的domain信息,方便当期域cookie写入,实现跨域登录。
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等中间件代理接口访问nginx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不为cookie时,可为*add-header Access-Control-Allow-Credentials true;}}
前端代码示例:
const xhr = new XMLHttpRequest();// 前端开关:浏览器是否读写Cookiexhr.withCredentials = true;// 访问nginx中的代理服务器xhr.open('get','http://www.domain1.com:81/?user=domain',true);xhr.send();
node后端示例:
var http = require('http');var server = http.createServer();var qs = require('querystring');server.on('request', function(req, res) {var params = qs.parse(req.url.substring(2));// 向前台写cookieres.writeHead(200, {'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取});res.write(JSON.stringify(params));res.end();});server.listen('8080');console.log('Server is running at port 8080...');
