跨域请求

什么是跨域请求?javascript

当浏览器执行一个脚本时会检查是否同源,只有同源的脚本才会执行,若是不一样源即为跨域html

什么是同源?前端

同源即:由Netscape提出的著名安全策略,是浏览器最核心、基本的安全功能,它限制了一个源(origin)中加载文本或者脚本与来自其余源(origin)中资源的交互方式
,所谓的同源就是指协议、域名、端口相同。java

只要协议、域名、端口有任何一个不一样,都被看成是不一样的域,之间的请求就是跨域操做。

协议?域名?端口?web

协议:网络协议遍布OSI通讯模型(OSI七层模型,经常使用协议有TCP/IP、HTTP、FTP协议等)
域名:Domain Name,网域,是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)
端口:是设备与外界通信交流的出口,分为物理端口和虚拟端口(常见的如80端口)json

了解概念后咱们知道跨域请求就是web浏览器自身不容许在域名、协议、端口等都不相同的状况下进行页面请求方为,所以做为前端developer在项目开发时是须要解决此类问题的!后端

为何要有这种限制?非同源请求页面会怎么样?跨域

设想这样一个情景:A网站是一家银行,用户登陆之后,又去浏览其余的网站B,若是网站B能够读取A网站的Cookie,会发生什么问题?
显然,若是Cookie包含隐私(好比存款总额),这些信息就会泄露,更可怕的是,Cookie每每用来保存用户的登陆状态,若是用户没有退出登陆,其余网站就能够冒用户,随心所欲。由于浏览器同时还规定,提交表单不受同源策略的限制。浏览器

非同源限制范围安全

  • Cookie、LocalStorage和IndexDB没法获取
  • DOM没法得到
  • AJAX请求不能发送

跨域请求解决方案

1. jsonp:(JSON with Padding是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题)
原理:网页客户端动态添加<script>标签添加src属性,向服务端发送json请求(不受同源策略束缚)服务器收到请求后,将数据放在一个指定名字的回调函数里(做为参数)传回来。

// 前端请求代码
    //http://127.0.0.1:8888/jsonp.html
var script = document.createElement('script');
      script.src = 'http://127.0.0.1:2333/jsonpHandler?callback=_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) + ')');
})

JSONP只支持Get请求方式


2.CORS:(跨域资源共享)是由W3C制定的跨站资源分享标准,可让AJAX实现跨域访问,除了 GET 要求方法之外也支持其余的 HTTP 要求。服务器通常须要增长以下响应头的一种或几种:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

跨域请求默认不会携带Cookie信息,若是须要携带,请配置下述参数:

"Access-Control-Allow-Credentials": true
// Ajax设置
"withCredentials": true

3.window.name+iframe:利用iframe标签的跨域能力,window.name属性值在文档刷新后依旧存在的能力(且最大容许2M左右)

<!-- 
 下述用端口 
 10000表示:domainA
 10001表示:domainB
-->

<!-- localhost:10000 -->
<script>
  var iframe = document.createElement('iframe');
  iframe.style.display = 'none'; // 隐藏

  var state = 0; // 防止页面无限刷新
  iframe.onload = function() {
      if(state === 1) {
          console.log(JSON.parse(iframe.contentWindow.name));
          // 清除建立的iframe
          iframe.contentWindow.document.write('');
          iframe.contentWindow.close();
          document.body.removeChild(iframe);
      } else if(state === 0) {
          state = 1;
          // 加载完成,指向当前域,防止错误(proxy.html为空白页面)
          // Blocked a frame with origin "http://localhost:10000" from accessing a cross-origin frame.
          iframe.contentWindow.location = 'http://localhost:10000/proxy.html';
      }
  };

  iframe.src = 'http://localhost:10001';
  document.body.appendChild(iframe);
</script>

<!-- localhost:10001 -->
<!DOCTYPE html>
...
<script>
  window.name = JSON.stringify({a: 1, b: 2});
</script>
</html>

4.window.name:window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。

<script> //a页面设置
window.name="kowalski";
</script>
<script> //b页面取出
alert(window.name);
</script>

正在接触后续补充...

相关文章
相关标签/搜索