跨域HTTP請求解決方案

持續更新地址:http://jaylin.wang/2017/cross...html

跨域HTTP請求是指當前文檔訪問其餘源提供的資源。兩個頁面具備相同的協議,域名和端口,則兩個頁面屬於相同的源,不一樣子域名之間也屬於不一樣的源。這是瀏覽器端的同源策略的約束,同源策略則是瀏覽器隔離潛在惡意文件的安全機制。git

目前經常使用的跨域解決方案有EmbedPing、JSONP、CORS。github

一些知識點

  1. 跨域限制是瀏覽器的一種行爲ajax

    當咱們在瀏覽器的一個頁面中嘗試進行一次跨域操做,好比咱們在 localhost 的一個頁面經過 ajax 訪問 127.0.0.1 的一個路由,127.0.0.1已經將數據返回給瀏覽器,瀏覽器禁止了獲取響應數據行爲。咱們能夠看一張圖:json

    跨越請求現象

  2. 跨域請求的幾種方式跨域

    • 跨域寫
      瀏覽器始終支持經過跨域寫操做。例如經過表單提交方式向其餘源提交數據,點擊連接重定向到其餘源。瀏覽器

    • 跨域嵌入
      瀏覽器始終支持跨域資源的嵌入。例如經過 img、script、video 等元素的 src 屬性嵌入跨域資源。緩存

    • 跨域讀安全

跨域的解決方案

EmbedPing

這是我本身瞎取的一個名字,大體是利用瀏覽器支持標籤嵌入跨域屬性實現的一種方案。img、script、link[rel='stylesheet']會在頁面渲染過程當中請求其src/href設置的資源地址,咱們能夠在訪問的路由中作處理。例如使用img的src屬性:服務器

<script>
    var img = new Image()
    img.src = 'http://localhost:4000/check'
  </script>

由於沒法獲取到服務端返回的數據,EmbedPing是瀏覽器向服務器單向請求的過程。

咱們可使用 EmbedPing 作一些不嚴格統計。

JSONP

JSONP也利用了 script 標籤的 src 屬性,瀏覽器會執行加載成功後的js。JSONP的侷限是隻能發送一個GET請求。

應用示例

看一個簡單示例,咱們但願在當前域的頁面上打印服務器的一個狀態,咱們使用JSONP能夠這樣實現,前能夠看一段簡單代碼(服務端使用koa構建的):

當前域屬於 http://localhost:3000,咱們在頁面上這請求

<body>
  <script>
    var script = document.createElement('script')
    script.src = 'http://localhost:4000/jsonp/run'
    script.async = true
    document.body.appendChild(script)
  </script>
</body>

http://localhost:4000/jsonp/run 中,咱們返回了一段打印狀態的script

var valForServerB = 'a'
router.get('/jsonp/run', (ctx) => {
  let script = `
    alert('我來自服務器b,個人值是${valForServerB}')
  `
  ctx.body = script
})

這樣,咱們能夠在當前頁面上顯示 valForServerB 的值了。

幾種類型

根據 JSONP 返回的代碼片斷不一樣,混入本身的情感,我將 JSONP 分爲三種類型(這種帶着情感的劃分,須要各位大牛的指正):

  • 返回執行
    返回代碼即執行代碼,直接在頁面上產生效果

  • 返回定義
    返回代碼是函數的定義,具體調用時機交給當前頁面決定

  • 返回調用
    函數的執行過程是在頁面上所定義的,JSONP的返回只是函數的調用,固然包含傳給函數的參數。

爲了保持當前頁面的的絕對控制權,返回調用應該是應用最廣的

錯誤處理

JSONP使用過程當中,會有兩種常見錯誤:

  • 請求失敗或服務器返回失敗
    捕獲此類錯誤,咱們是借用 script 的 onerror 處理

  • 服務器返回內容錯誤
    針對這類錯誤,咱們會在當前頁面借用定時器去處理。在返回調用時,咱們能夠在頁面上的函數定義中埋下時間因子;在返回定義時,咱們能夠設置時間點去檢測指望調用的方法是否存在。固然,此方法會由於網絡等因素變得不可靠。

CORS(跨域資源共享)

CORS是當前頁面與其餘域執行的一種雙方約束,須要瀏覽器應用和服務器程序之間的協調。

咱們在服務器端能夠經過設置CORS響應頭部:

  • Access-Control-Allow-Origin: <origin> | *
    容許訪問的源

  • Access-Control-Allow-Methods
    容許訪問的方法

  • Access-Control-Allow-Headers
    運行添加的請求頭部

  • Access-Control-Expose-Headers
    容許客戶端能夠訪問的頭部

  • Access-Control-Max-Age
    預請求的緩存週期

  • Access-Control-Allow-Credentials
    是否運行請求加入用戶憑證信息

相應的,在請求頭部中,咱們能夠加入:

  • Origin
    告知服務器請求的源

  • Access-Control-Request-Method
    告知服務器使用請求的的方法

  • Access-Control-Request-Headers
    告知服務器,請求中攜帶的頭部

結語

跨域請求好,安全第一位。在咱們跨域請求時,咱們要確保咱們請求的服務器返回的數據是可信任的。

相關連接

cross-origin-resolve-demo

MDN CORS

相關文章
相關標籤/搜索