跨域請求

什麼是跨域請求?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>

正在接觸後續補充...

相關文章
相關標籤/搜索