關於跨域問題

面試必考題吧,因此在這會詳細介紹如下內容git

  1. 跨域產生的緣由
  2. 羅列最經常使用的解決方法
  3. 分析各類方法原理
  4. 羅列各類方法優缺點

什麼是跨域

因爲瀏覽器廠商對安全性的考慮,提出了瀏覽器的同源策略作爲解決方案。它是一個用於隔離潛在惡意文件的重要安全機制。同源即協議域名端口三者一致。不一樣源即跨域。github

若是沒有同源策略會怎麼樣?

好比:當你訪問了 餅夕夕的網站面試

// HTML
// 餅夕夕.com 內嵌 拼多多.com
<iframe name="pinduoduo" src="www.pinduoduo.com"></iframe>

// JS
// 因爲沒有同源策略的限制,釣魚網站能夠直接拿到別的網站的Dom
// 因此 餅夕夕.com 能夠在 拼多多.com 輸入帳號密碼處埋點
const $iframe = window.frames['pinduoduo'];
const $pwd = $iframe.document.getElementById('password');
console.log(`你的密碼已泄露: ${$pwd}`)
複製代碼

解決方案(主流)

1. JSONP -> get請求跨域 原理:script和img等標籤沒有跨域限制 實現方案:(舉例)ajax

// HTML 插入標籤
  <script src="127.0.0.1/x/account?cb=say" ></script>

  // JS
  function say(name, age) {
    console.log(`${name}, ${age} 歲`)
  }

  // 服務器返回response
  say('zmz', 18)

  // 那麼客戶端在script onload時會執行say方法

  // 結束
複製代碼

2. iframe+form實現post請求跨域 原理:利用form表單target屬性,將post請求提交給隱藏的iframe,使頁面不跳轉json

var data = {
    name: 'zmz',
    age: 18
  }
  var url = 'http://localhost/say';

  var $iframe = document.createElement('iframe');
  $iframe.name = 'iframePost';
  $iframe.style.display = 'none';
  document.body.appendChild($iframe);
  
  $iframe.addEventListener('load', function(e) {
    console.log($iframe.contentWindow)
  })
  
  const form = document.createElement('form');
  const ipt = document.createElement('input');
  form.action = url;
  form.enctype = 'application/json;'
  form.method = 'post';

  // 最核心的一行代碼
  // 在指定的iframe中執行form
  form.target = $iframe.name;

  for (var name in data) {
      ipt.name = name;
      ipt.value = data[name]; 
      form.appendChild(ipt.cloneNode());
  }
  form.style.display = 'none';
  document.body.appendChild(form);
  form.submit();
  
  document.body.removeChild(form)
複製代碼

3. CORS 跨源資源共享 原理:新版XMLHttpRequest(ajax2.0)特性,服務器白名單 服務器端設置response.setHeader("Access-Control-Allow-xxx...api

附:ajax2.0新特性跨域

  • 能夠設置HTTP請求的時限xhr.timeout
  • 可使用FormData對象管理表單數據
  • 能夠上傳文件 >> 同上
  • 能夠請求不一樣域名下的數據(跨域請求)
  • 能夠獲取服務器端的二進制數據xhr.responseType = 'blob'
  • 能夠得到數據傳輸的進度信息 xhr.upload.process

CORS分類瀏覽器

  • 簡單請求(自行搜索)
    • 在請求頭信息中指定Origin
  • 非簡單請求
    • 會發送預檢請求(options),返回狀態碼204

5. 代理 原理:服務器之間沒有跨域限制 具體實現:安全

// Nginx配置
  server{
    # 監聽9099端口
    listen 9099;
    # 域名是localhost
    server_name localhost;
    # 匹配到都轉發到http://localhost:9871 
    location ^~ /api {
        proxy_pass http://localhost:9871;
    }    
}
複製代碼

5. postMessage 原理:postMessage能夠處理各類瀏覽器窗口之間的通訊問題。 具體實現:bash

// 發送方
  window.frames['crossDomainIframe']
  iframe.postMessage('我想要數據', 'http://localhost:8088')

  window.addEventListener('message', function () {
    if (e.origin === 'http://localhost:2333') {
      console.log('收到', e.data)
    }
  }

  // 接收方
  window.addEventListener('message', (e) => {
    if (e.origin === 'http://localhost:8088') {
      console.log(e.data)
      e.source.postMessage('給,你要的數據', e.origin);
    }
  })
複製代碼

6. WebSocket 原理:新協議(socket) 實現方案:相似postMessage 附:

  • socket.io框架能解決兼容性問題

各類方式對比

  • JSONP和iframe+from兼容性很好
    • 可是錯誤處理和RESTful接口統一是個問題
  • CORS最簡單粗暴
    • 9102年了。微軟都不維護Win7了。
  • 代理
    • 確定會慢一丟丟咯,並且要找運維配
  • postMessage
    • 處理窗口間通訊,- -。不嫌麻煩能夠用來跨域
  • WebSocket
    • 處理長鏈接,附帶跨域

End

文章分享同步於: github.com/zhongmeizhi…

相關文章
相關標籤/搜索
每日一句
    每一个你不满意的现在,都有一个你没有努力的曾经。