• web 通信类


    1、什么是同源策略级限制?

    2、前后端如何通信?

    3、如何创建ajax?

    4、跨域通信的几种方式?

    什么是同源策略限制:

    先解释什么是源,然后再解释

    源:协议,域名,端口  三个有其中一个不一样,就是不同源,

    就是不是同一个源不能操作另外一个源的东西

    主要限制在以下三个方面:

    cookie、localstorage 和indexDB无法读取

    DOM无法获得

    ajax请求不能发送

    前后端如何通信

    Ajax(同源策略限制)  WebSocket(不受同源策略限制)  CORS(支持同源也支持不同源)

    如何创建ajax?

    XMLHttpRequest对象的工作流程

    兼容性处理

    事件触发的条件

    事件的触发顺序

    创建对象xhr ->open() ->send() 

    响应 xhr.onload = function(){}

    /**
    * [json 实现ajax的json]
    * @param {[type]} options [description]
    * @return {[type]} [description]
    */
    util.json = function (options) {
    var opt = {
    url: '',
    type: 'get',
    data: {},
    success: function () {},
    error: function () {},
    };
    util.extend(opt, options);
    if (opt.url) {
    var xhr = XMLHttpRequest
    ? new XMLHttpRequest()
    : new ActiveXObject('Microsoft.XMLHTTP');
    var data = opt.data,
    url = opt.url,
    type = opt.type.toUpperCase(),
    dataArr = [];
    for (var k in data) {
    dataArr.push(k + '=' + data[k]);
    }
    if (type === 'GET') {
    url = url + '?' + dataArr.join('&');
    xhr.open(type, url.replace(/?$/g, ''), true);
    xhr.send();
    }
    if (type === 'POST') {
    xhr.open(type, url, true);
    xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(dataArr.join('&'));
    }
    xhr.onload = function () {
    if (xhr.status === 200 || xhr.status === 304) {
    var res;
    if (opt.success && opt.success instanceof Function) {
    res = xhr.responseText;
    if (typeof res ==== 'string') {
    res = JSON.parse(res);
    opt.success.call(xhr, res);
    }
    }
    } else {
    if (opt.error && opt.error instanceof Function) {
    opt.error.call(xhr, res);
    }
    }
    };
    }
    };

    跨域通信的几种方式

    JSONP:img中的src,link的href,script 中的src这三个都不符合同源策略,但是它们都能跨域获取资源,jsonp就是利用script的这个特点来实现跨域获取数据的

    它只支持GET请求而不支持POST等其它类型的HTTP请求

    jsonp是由两部份组成的,回调函数和数据

    Hash: url#后面的就是hash,hash改变,页面不刷新 缺点:另外由于URL大小的限制,支持传递的数据量也不大。

    postMessage:

    优缺点:

     优点:方便,安全,有效的解决了跨域问题

     缺点:万恶的资本主义,ie8+才支持,而且ie8+<ie10只支持iframe的方式。

    WebSocket:是一种网络协议,与http的差异是:http仅当客户端向服务器发送请求的时候,服务器才会向客户端发送信息,而websocket服务器可以主动向客户端发送信息,客户端也可以向服务器主动发送信息。此协议没有同源限制,协议标识符是 ws,加密后的是wss 详细见http://www.ruanyifeng.com/blog/2017/05/websocket.html

    CORS:

    它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制

    CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

     浏览器发出CROS请求,就是在头信息增加一个origin字段,这个字段用来说明本次请求来自哪个源,服务器会根据这个源绝对是否同意这次请求

    jsonp

        <div class="left" id="left">left</div>
    <div class="right">right</div>
    </section>
    <script type="text/javascript" charset="utf-8">
    document.getElementById('left').onclick = function () {
    var script = document.createElement('script');
    script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
    document.body.insertBefore(script,document.body.firstChild)
    }
    function handleResponse(res){
    console.log('res',res)
    }
    </script>

    hash

    原理是利用location.hash来进行传值。

    假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息。

    1) cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面

    2) cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据

    3) 同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值

    注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe

    代码如下:

    先是a.com下的文件cs1.html文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function startRequest(){
     var ifr = document.createElement('iframe');
     ifr.style.display = 'none';
     document.body.appendChild(ifr);
    }
     
    function checkHash() {
     try {
      var data = location.hash ? location.hash.substring(1) : '';
      if (console.log) {
       console.log('Now the data is '+data);
      }
     } catch(e) {};
    }
    setInterval(checkHash, 2000);

    cnblogs.com域名下的cs2.html:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //模拟一个简单的参数处理操作
    switch(location.hash){
     case '#paramdo':
      callBack();
      break;
     case '#paramset':
      //do something……
      break;
    }
     
    function callBack(){
     try {
      parent.location.hash = 'somedata';
     } catch (e) {
      // ie、chrome的安全机制无法修改parent.location.hash,
      // 所以要利用一个中间的cnblogs域下的代理iframe
      var ifrproxy = document.createElement('iframe');
      ifrproxy.style.display = 'none';
      ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata'; // 注意该文件在"a.com"域下
      document.body.appendChild(ifrproxy);
     }
    }

    a.com下的域名cs3.html

    1
    2
    //因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
    parent.parent.location.hash = self.location.hash.substring(1);

    // 利用hash,场景是当前页面 A 通过iframe或frame嵌入了跨域的页面 B
    /

    postMessage

    postMessage实现跨域

       语法:window.postMessage(msg,targetOrigin)

        window: 指目标窗口,可能是window.frames属性的成员或者由window.open方法创建的窗口

        message:要发送的消息,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果

        targetOrigin:“目标域“,包括:协议、主机名、端口号。若指定为”*“,则表示可以传递给任意窗口,指定为”/“,则表示和当前窗口的同源窗口。

        获取postMessage传来的消息:为页面添加onmessage事件

    1 window.addEventListener('message',function(e) {
    2     
    3 }

        onmessage事件接受一个参数e,它是一个event对象。

        e的几个重要属性:

          1、data:postMessage传递过来的msg

          2、发送消息的窗口对象

          3、origin:发送消息窗口的源(协议+主机+端口号)

         来写一个简单的demo:

         http://source.com/source.html用来发送数据:

    1 <iframe id="iframe" src="http://target.com/target.html"></iframe>
    2 <input id="msg" type="text" placeholder="请输入要发送的消息">
    3 <button id="send">发送</button>
    复制代码
    1 window.onload =function() {
    2     document.getElementById('send').onclick = function() {
    3     var msg = document.getElementById('msg').value;
    4     var iframeWindow = document.getElementById('iframe').contentWindow;
    5     iframeWindow.postMessage(msg,"http://target.com/target.html");
    6     }
    7 }
    复制代码

         http://target.com/target.html用来接收数据:  

    1 <div>
    2     <h2>target.html,以下是接收到的消息:</h2>
    3     <section id="msg">
    4         
    5     </section>
    6 </div>
    复制代码
     1 window.onload = function() {
     2 
     3     if(window.addEventListener){
     4         window.addEventListener("message", handleMessage, false);
     5     }
     6     else{
     7         window.attachEvent("onmessage", handleMessage);
     8     }  
     9 
    10     function handleMessage(event) {
    11         event = event || window.event;
    12 
    13         if(event.origin === 'http://source.com') {
    14             document.getElementById('msg').innerHTML = event.data;
    15         }
    16     }
    17 }
    复制代码

    // Websocket【参考资料】http://www.ruanyifeng.com/blog/2017/05/websocket.html

    var ws = new WebSocket('wss://echo.websocket.org');

    ws.onopen = function (evt) {
    console.log('Connection open ...');
    ws.send('Hello WebSockets!');
    };

    ws.onmessage = function (evt) {
    console.log('Received Message: ', evt.data);
    ws.close();
    };

    ws.onclose = function (evt) {
    console.log('Connection closed.');
    };

    // CORS【参考资料】http://www.ruanyifeng.com/blog/2016/04/cors.html
    // url(必选),options(可选)
    fetch('/some/url/', {
    method: 'get',
    }).then(function (response) {

    }).catch(function (err) {
    // 出错了,等价于 then 的第二个参数,但这样更好用更直观
    });

  • 相关阅读:
    Flask-数据库操作
    Flask-模板
    Flask-路由和视图
    Python调用摄像头
    Python操作mysql
    Java数据结构-栈
    SpringBoot前端使用JSP
    SpringBoot的核心配置文件
    第一个SpringBoot项目
    17.1.2 流、缓冲区和iostream文件
  • 原文地址:https://www.cnblogs.com/liangshuang/p/8495449.html
Copyright © 2020-2023  润新知