同源策略

所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个IP地址,也非同源。
同源策略限制以下几种行为:

  • Cookie、LoaclStorage 和 IndexDB 无法读取
  • DOM 和 Js对象无法获得
  • Ajax 请求不能发送

    跨域解决方案

    JSONP

    通常为了减轻web服务器的负载,我们把js、css、img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。 ```javascript const script = document.createElement(‘script’); script.type = ‘text/javascript’;

// 传参一个回调函数名给后端,后端返回时将参数传入并执行这个在前端定义的回调函数

  1. <a name="KSzHH"></a>
  2. #### 跨域资源共享(CORS)
  3. 普通跨域请求:服务端只需设置Access-Control-Allow-Origin即可,前端无需设置,若要带Cookie请求:前后端都需要设置。
  4. 需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
  5. <a name="4yLvX"></a>
  6. ##### 前端设置
  7. 原生Ajax
  8. ```javascript
  9. var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
  10. // 前端设置是否带cookie
  11. xhr.withCredentials = true;
  12. xhr.open('post', 'http://www.domain2.com:8080/login', true);
  13. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  14. xhr.send('user=admin');
  15. xhr.onreadystatechange = function() {
  16. if (xhr.readyState == 4 && xhr.status == 200) {
  17. alert(xhr.responseText);
  18. }
  19. };

axios

  1. axios.defaults.withCredentials = true;

node后端示例:

  1. const http = require('http');
  2. const server = http.createServer();
  3. const qs = require('qs');
  4. server.on('request',function(req,res){
  5. let postData = '';
  6. // 数据块接收中
  7. req.addListener('data',function(chunk){
  8. postData += chunk;
  9. })
  10. // 数据接收完毕
  11. req.addListen('end',function(){
  12. postData = qs.parse(postData);
  13. // 跨域后台设置
  14. res.writeHead(200,{
  15. 'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
  16. 'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域
  17. /*
  18. * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写Cookie(nginx反向代理可以实现)
  19. * 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有接口都能跨域访问
  20. */
  21. 'Set-Cookie': 'l-a123456;Path:/;Domain=www.domain2.com;HttpOnly'
  22. })
  23. res.write(JSON.stringify(postData));
  24. res.end();
  25. })
  26. })
  27. server.listen(3000)

nginx代理跨域

nginx配置解决iconfont跨域

浏览器跨域访问 js, css, img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态服务器中加入以下配置:

  1. location / {
  2. add_header Access-Control-Allow-Origin *;
  3. }

nginx反向代理接口跨域

跨域原理:同源策略是浏览器的安全策略,不是Http协议的一部分。服务器端调用Http接口只是使用Http协议,不会执行JS脚本,不需要同源策略,也就不存在跨域问题。

实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中的domain信息,方便当期域cookie写入,实现跨域登录。

nginx具体配置:

  1. #proxy服务器
  2. server {
  3. listen 81;
  4. server_name www.domain1.com;
  5. location / {
  6. proxy_pass http://www.domain2.com:8080; # 反向代理
  7. proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
  8. index index.html index.htm;
  9. # 当用webpack-dev-server等中间件代理接口访问nginx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
  10. add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不为cookie时,可为*
  11. add-header Access-Control-Allow-Credentials true;
  12. }
  13. }

前端代码示例:

  1. const xhr = new XMLHttpRequest();
  2. // 前端开关:浏览器是否读写Cookie
  3. xhr.withCredentials = true;
  4. // 访问nginx中的代理服务器
  5. xhr.open('get','http://www.domain1.com:81/?user=domain',true);
  6. xhr.send();

node后端示例:

  1. var http = require('http');
  2. var server = http.createServer();
  3. var qs = require('querystring');
  4. server.on('request', function(req, res) {
  5. var params = qs.parse(req.url.substring(2));
  6. // 向前台写cookie
  7. res.writeHead(200, {
  8. 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
  9. });
  10. res.write(JSON.stringify(params));
  11. res.end();
  12. });
  13. server.listen('8080');
  14. console.log('Server is running at port 8080...');