前端跨域问题

前端常见问题和技术解决方案

1、同源策略

浏览器同源策略限制请求

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

限制以下行为

  1. Cookie、LocalStorageIndexDB 无法读取
  2. DOM 和 Js对象无法获得
  3. AJAX 请求不能发送

有三个标签是允许跨域加载资源:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

2、解决方案

1)通过jsonp跨域

script标签不受策略影响,可以动态生成script去请求数据,但是仅限Get请求

原生实现

<script>
  var script = document.createElement('script');
  script.type = 'text/javascript';   
  // 传参并指定回调执行函数为onBack
  script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';    
  document.head.appendChild(script);    
  // 回调执行函数
  function onBack(res) {
    alert(JSON.stringify(res));
  } 
</script>

vue实现

this.$http.jsonp(
  'http://www.domain2.com:8080/login', 
   {    
     params: {},    
    jsonp: 'onBack'
   }
  ).then(res => { console.log(res); }
)

2)document.domain + iframe跨域

仅限主域相同,子域不同的跨域应用场景

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域

<!-- 父窗口:http://www.domain.com/a.html -->
<iframe id="iframe" src="http://child.domain.com/b.html">
</iframe>

<script>
  document.domain = 'domain.com';    
  var user = 'admin';
</script>

<!-- 子窗口:http://child.domain.com/b.html -->
<script>
  document.domain = 'domain.com';    
  // 获取父窗口中变量
  alert('get js data from parent ---> '+ window.parent.user);
</script>

3)location.hash + iframe

实现原理: a与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframelocation.hash传值,相同域之间直接js访问来通信。
具体实现:
A域:a.html -> B域:b.html -> A域:c.html,
a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。

4)window.name + iframe跨域

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

5) postMessage跨域

postMessage一般用于解决以下问题

a.) 页面和其打开的新窗口的数据传递

b.) 多窗口之间消息传递

c.) 页面与嵌套的iframe消息传递

d.) 上面三个场景的跨域数据传递

<!-- a页面:http://www.domain1.com/a.html -->
<iframe id="iframe" 
        src="http://www.domain2.com/b.html" 
        style="display:none;">
</iframe>
<script>       
  var iframe = document.getElementById('iframe');
  iframe.onload = function() {        
    var data = {           
      name: 'aym'
    };        
    // 向domain2传送跨域数据
    iframe.contentWindow.postMessage
    (JSON.stringify(data),
     'http://www.domain2.com');
  };    
  // 接受domain2返回数据
  window.addEventListener
  ('message', function(e) {
    alert('data from domain2 ---> ' + e.data);
  }, 
   false);
</script>

<!-- b页面:http://www.domain2.com/b.html -->
<script>
  // 接收domain1的数据
  window.addEventListener
  ('message', function(e) {
    alert('data from domain1 ---> ' + e.data);        
    var data = JSON.parse(e.data);        
    if (data) {
      data.number = 16;            
      // 处理后再发回domain1
      window.parent.postMessage(JSON.stringify(data),
                                'http://www.domain1.com');
    }
  }, false);
</script>

6)跨域资源共享(CORS):主流的跨域解决方案

服务端设置Access-Control-Allow-Origin即可

若要带cookie请求:前后端都需要设置。

前端: : 检查前端设置是否带cookie:xhr.withCredentials = true;

通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求复杂请求

简单请求:

使用下列方法之一:

  • GET
  • HEAD
  • POST
    Content-Type 的值仅限于下列三者之一:
  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求, 该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

OPTIONS预检请求

请求头:

  • Origin:当前请求源,和响应头里的Access-Control-Allow-Origin 对标, 是否允许当前源访问,Origin是不可修改的
  • Access-Control-Request-Headers:本次真实请求的额外请求头,和响应头里的Access-Control-Allow-Headers对标,是否允许真实请求的请求头
  • Access-Control-Request-Method:本次真实请求的额外方法,和响应头里的Access-Control-Allow-Methods对标,是否允许真实请求使用的请求方法

7)nginx代理跨域

nginx配置解决iconfont跨域

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

location / {
  add_header 
  Access-Control-Allow-Origin *;
}

反向代理

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

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

#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;
  }
}

8)WebSocket协议跨域

WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。

原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

<div>user input:
  <input type="text">
</div>

<script src="./socket.io.js"></script>
<script>var socket = io('
                        http://www.domain2.com:8080');
                        // 连接成功处理
                        socket.on('connect', function() {    
    // 监听服务端消息
    socket.on('message', function(msg) {        
      console.log('data from server: ---> ' + msg); 
    });   
    // 监听服务端关闭
    socket.on('disconnect', function() { 
      console.log('Server socket has closed.'); 
    });
  });
  document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
  };
 </script>

转载:前端常见问题和技术解决方案

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值