跨域请求的几种实现方式

什么是跨域

跨域是由于浏览器的同源策略导致的,所谓的同源就是指协议、域名、端口相同。当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,如果不同源即为跨域。(也就是跨域发生在浏览器阶段,当请求一个跨域资源时,服务器会返回相应的脚本,但是浏览器并不会执行)

实现跨域的几种方式

1、JSONP

最常见的一种跨域方式,其背后原理就是利用了script标签不受同源策略的限制,在页面中动态插入了script,script标签的src属性就是后端api接口的地址,并且以get的方式将前端回调处理函数名称告诉后端,后端在响应请求时会将回调返还,并且将数据以参数的形式传递回去。

前端:

//http://127.0.0.1:8888/jsonp.html
var script = document.createElement('script');
script.src = 'http://127.0.0.1:2333/jsonpHandlercallback=_callback'
      document.body.appendChild(script);      //插入script标签
      //回调处理函数 _callback
      var _callback = function(obj){
          for(key in obj){
            console.log('key: ' + key +' value: ' + obj[key]);
          }
      }

后端:

//http://127.0.0.1:2333/jsonpHandler
app.get('/jsonpHandler', (req,res) => {
  let callback = req.query.callback;
  let obj = {
    type : 'jsonp',
    name : 'weapon-x'
  };
  res.writeHead(200, {"Content-Type": "text/javascript"});
  res.end(callback + '(' + JSON.stringify(obj) + ')');
})

优点:不需要后端做配置工作只需按需求把响应格式的JSON放在回调函数中返回即可。
缺点:
1. 不支持POST请求。
2. 不是XHR请求,不容易判断请求失败,大多数前端工具判断失败是结合请求超时来实现。
3. 容易造成XSS漏洞,通过往请求里嵌入恶意脚本形成XSS攻击。

2、CORS跨资源共享

通过XHR实现Ajax通信一个主要限制,来源于跨域安全策略。默认情况下,对XHR对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。

CORS是W3C的一个工作草案,定义了在必须进行访问跨源资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。

比如一个简单的使用GET或者POST发送的请求,它没有自定位的头部,而主体内容是text/plain。在发送该请求时,需要给它附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名、端口号),以便服务器根据这个头部信息决定是否给予响应。下面是Origin头部的一个示例:

Orgin: http://www/ncline.net

如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中回发相同的源信息(如果是公共信息,可以发”*”)。例如:

Access-Control-Allow-Origin: http://www/ncline.net

如果没有这个头部,或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。注意:请求和响应都不应包含cookie信息。

前端:

//http://127.0.0.1:8888/cors.html
var xhr = new XMLHttpRequest();
xhr.onload = function(data){
  var _data = JSON.parse(data.target.responseText)
  for(key in _data){
    console.log('key: ' + key +' value: ' + _data[key]);
  }
};
xhr.open('POST','http://127.0.0.1:2333/cors',true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send();

后端:

//http://127.0.0.1:2333/cors
app.post('/cors',(req,res) => {
  if(req.headers.origin){
    res.writeHead(200,{
      "Content-Type": "text/html; charset=UTF-8",
      "Access-Control-Allow-Origin":'http://127.0.0.1:8888'
    });
    let people = {
      type : 'cors',
      name : 'weapon-x'
    }
    res.end(JSON.stringify(people));
  }
})

优点:W3C发布的正式跨域标准,浏览器厂商都会跟进
缺点:部分桌面浏览器不支持,例如:ie6、7。目前大部分应用在移动端。

3、window.name

原理:window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的。

这里有三个页面:

sever.com/a.html 数据存放页面

agent.com/b.html 数据获取页面

agent.com/c.html 空页面,做代理使用

a.html中,设定 window.name 作为需要传递的值
<script>
 window.name = 'I was there!';
 alert(window.name);
</script>

b.html中,当iframe加载后将iframe的 src 指向同域的 c.html ,这样就可以利用 iframe.contentWindow.name 获取要传递的值了

<body>
  <script type="text/javascript">
 iframe = document.createElement('iframe');
 iframe.style.display = 'none';
 var state = 0;
 iframe.onload = function() {
 if(state === 1) {
 var data = JSON.parse(iframe.contentWindow.name);
 alert(data);
 iframe.contentWindow.document.write('');
 iframe.contentWindow.close();
 document.body.removeChild(iframe);
 } else if(state === 0) {
 state = 1;
 iframe.contentWindow.location = 'http://agent.com/c.html';
 }
 };
 iframe.src = 'http://sever.com/a.html';
 document.body.appendChild(iframe);
 </script>
</body>

4、后台代理

这种方式可以解决所有跨域问题,也就是将后台作为代理,每次对其它域的请求转交给本域的后台,本域的后台通过模拟http请求去访问其它域,再将返回的结果返回给前台,这样做的好处是,无论访问的是文档,还是js文件都可以实现跨域。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值