【知識梳理】3.8通訊類

1.同源策略及限制

:協議(http://)、域名(www.example.com)、端口(80)javascript

同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。html

目的:這是一個用於隔離潛在惡意文件的關鍵的安全機制。java

限制範圍:web

  • Cookie、LocalStorage 和 IndexDB 沒法讀取;
  • DOM 沒法得到;
  • AJAX 請求不能發送。

參考文檔:瀏覽器同源政策及其規避方法ajax

能夠跨域的三個標籤json

  1. <img src="xxx.png">
  2. <link href="xxx">
  3. <script src="xxx">

三個標籤的場景segmentfault

  1. <img>,用於打點統計,統計網站多是其餘域;
  2. <link><script>,可使用CDN,CDN的也是其餘域;
  3. <script>,能夠用於jsonp

2.先後端通訊

  • Ajax(僅支持同源通訊)
  • WebSocket(支持同源、跨域)
  • CORS(支持同源、跨域)

3.手動編寫一個ajax

  1. 處理IE兼容性問題,
var xhr = XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
  1. readyState後端

    • 0,(未初始化)尚未調用send()方法;
    • 1,(載入)已經調用send()方法,正在發送請求;
    • 2,(載入完成)send()方法執行完成,已經接收到所有相應內容;
    • 3,(交互)正在解析響應內容;
    • 4,(完成)響應內容解析完成,能夠再客戶端調用了。
  2. statusapi

    • 2**,表示成功處理請求,如200;
    • 3**,須要重定向,瀏覽器直接跳轉;
    • 4**,客戶端請求錯誤,如404;
    • 5**,服務器端錯誤。
var xhr = new XMLHttpRequest();
xhr.open("GET","/api",false);
xhr.onreadystatechange = function(){
    //這裏的函數異步執行
    if(xhr.readyState == 4){
        if(xhr.status == 200){
            alert(xhr.responseText);
        }
    }
}
xhr.send(null);

4.建立Ajax

  • XMLHTTPRequest對象的工做流程
  • 兼容性處理
  • 事件的觸發條件
  • 事件的觸發順序

參考文檔:聊聊Ajax那些事跨域

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');//1.聲明對象,處理IE兼容性
         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);//2.open,肯定XMLHttpRequest對象的發送方式(用的那個協議:GET/POST等)
             xhr.send();//3.發送請求
         }
         if (type === 'POST') {
             xhr.open(type, url, true);
             xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
             xhr.send(dataArr.join('&'));
         }
         xhr.onload = function () {//4.響應
             if (xhr.status === 200 || xhr.status === 304 ||xhr.status === 206) {//206適用於接收部分媒體資源,304利用本地緩存
                 var res;
                 if (opt.success && opt.success instanceof Function) {
                     res = xhr.responseText;
                     if (typeof res ==== 'string') {
                         res = JSON.parse(res);//轉成JSON
                         opt.success.call(xhr, res);
                     }
                 }
             } else {
                 if (opt.error && opt.error instanceof Function) {
                     opt.error.call(xhr, res);
                 }
             }
         };
     }
 };

5.JSONP實現原理

<script>
//此處定義回調函數
window.callback = function(data){
    //這是咱們跨域獲得的信息
    console.log(data);
}
</script>

<script src="http://www.baidu.com/api.js"></script>
<!-- 以上將返回 callback({x:100,y:200}),此處執行回調函數 -->

6.跨域通訊的幾種方式

  • 1.JSONP

原理:經過script標籤的異步加載實現的;

//JSONP

//1.瀏覽器發送請求,告訴服務端callback的名稱
<script src="http://www.abc.com/?data=name&callback=jsonp" charset="utf-8"></script>

//2.服務器響應下發script內容,callback的名稱做爲函數名返回
<script>
    jsonp({
        data:{
        
        }    
    })
</script>

//代碼實現
 /**
  * [function 在頁面中注入js腳本]
  */
 util.createScript = function (url, charset) {
     var script = document.createElement('script');
     script.setAttribute('type', 'text/javascript');
     charset && script.setAttribute('charset', charset);
     script.setAttribute('src', url);
     script.async = true;
     return script;
 };
//本地須要有以callback的名稱建立函數
 util.jsonp = function (url, onsuccess, onerror, charset) {
     var callbackName = util.getName('tt_player');
     window[callbackName] = function () {
         if (onsuccess && util.isFunction(onsuccess)) {
             onsuccess(arguments[0]);
         }
     };
     var script = util.createScript(url + '&callback=' + callbackName, charset);
     script.onload = script.onreadystatechange = function () {
         if (!script.readyState || /loaded|complete/.test(script.readyState)) {
             script.onload = script.onreadystatechange = null;
             // 移除該script的 DOM 對象
             if (script.parentNode) {
                 script.parentNode.removeChild(script);
             }
             // 刪除函數或變量
             window[callbackName] = null;
         }
     };
     script.onerror = function () {
         if (onerror && util.isFunction(onerror)) {
             onerror();
         }
     };
     document.getElementsByTagName('head')[0].appendChild(script);
 };
  • 2.Hash

url地址中#後邊的叫Hash,Hash變更頁面不會刷新(Hash作跨域通訊的基本原理);
url地址中?後邊的叫search,search變更頁面會刷新頁面,因此search不能作跨域通訊。

// hash

      // 場景:當前頁面 A 經過iframe或frame嵌入了跨域的頁面 B,要給跨域的 B 發送消息

      // 在A中僞代碼以下:
      var B = document.getElementsByTagName('iframe');
      B.src = B.src + '#' + 'data';//經過JSON.stringify()轉成字符串'data'
      // 在B中的僞代碼以下
      window.onhashchange = function () {
          var data = window.location.hash;
      };
  • 3.postMessage

H5中新增長的實現跨域通訊的方式

// postMessage

      // 場景:窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息
      Bwindow.postMessage('data', 'http://B.com');
      // 在窗口B中監聽
      Awindow.addEventListener('message', function (event) {
          console.log(event.origin);//http://A.com
          console.log(event.source);//Awindow
          console.log(event.data);//data
      }, false);
  • 4.WebSocket
// Websocket

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

    //發送消息onopen
      ws.onopen = function (evt) {
          console.log('Connection open ...');
          ws.send('Hello WebSockets!');
      };
    //接收消息onmessage
      ws.onmessage = function (evt) {
          console.log('Received Message: ', evt.data);
          ws.close();
      };
    //關閉鏈接
      ws.onclose = function (evt) {
          console.log('Connection closed.');
      };

參考文檔:WebSocket 教程

  • 5.CORS

新的通訊標準(經過新的API:fetch()實現CORS通訊)。能夠理解爲:支持跨域通訊的Ajax。當你在瀏覽器中發送一個ajax跨域請求時,瀏覽器會在http頭中加入一個origin。若是隻是一個普通的ajax,跨域時就會被瀏覽器攔截。

// CORS
      
      // url(必選),options(可選)
      fetch('/some/url/', {
          method: 'get',
      }).then(function (response) {
        //then 回調
      }).catch(function (err) {
        // catch捕獲錯誤;出錯了,等價於 then 的第二個參數,但這樣更好用更直觀
      });

參考文檔:跨域資源共享 CORS 詳解

  • 6.服務器端設置 http header
//注意:不一樣後端語言的寫法可能不同

//第二個參數填寫容許跨域的域名城,不建議直接寫"*"
response.setHeader("Access-Control-Allow-Origin","http://a.com,http://b.com");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
response.addHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS");


//接受跨域的cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
相關文章
相關標籤/搜索