跨域請求產生錯誤的緣由及處理方法

若是你在開發網站時曾經嘗試經過框架或是瀏覽器的 fetchXHR 請求過外部 API 的話,那麼必定遇到過跨域請求,還有那個觸目驚心的 CORS 錯誤信息;今天我們來討論跨域問題的緣由以及解決方法。前端

跨域請求

若是你沒有沒有遇過,能夠試着在瀏覽器的 console 頁輸入下面的代碼:nginx

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
  if (xhr.readyState === 4) {
    console.log(xhr.status === 200 ? xhr.responseText : 'error')
  }
}
xhr.open('GET', 'https://google.com')
xhr.send()

這段代碼經過調用瀏覽器的 XMLHttpRequest 對 Google 發出請求,而獲得的結果如圖所示:程序員

image.png

這就是跨域請求問題,當經過 JavaScript 對不一樣的來源發送請求時,這個請求的響應就會被瀏覽器攔截,不交給 JavaScript 處理。這裏的「不一樣來源」指的是目標資源與當前網頁的域(domain)、通信協議(protocol)或網絡端口(port)只要有任一項不一樣,就算是不一樣來源。例以下面這幾個例子:面試

假設當前用戶在:https://example.com :
[✅] https://example.com/test -> 同域
[❌] https://m.example.com -> 不一樣域
[❌] https://example.com:3000 -> 端口不一樣
[❌] http://example.com -> 通信協議不一樣

理解什麼是跨域了,那爲何瀏覽器要把跨域請求資源攔截掉呢?segmentfault

其實這是考慮到用戶的信息安全。後端

假設小黑是一個惡意開發者,他編寫的網站會嘗試經過 XHR 打向百度、微博等目標網站;若是使用者原先就有目標網站的登陸狀態,小黑便能窺探他的隱私,獲得不應取得的數據。再想一想看,若是目標網站換成 Email、銀行、電商,若是沒有瀏覽器限制跨域請求的保護,惡意開發者便能隨心所欲。api

注意:跨域請求雖然會被瀏覽器攔截下來,但攔截的是響應(Response)而不是請求(Request)。

解決方案

關於跨域請求的解決方案有不少,例如 JSONP,也就是經過 HTML 中沒有跨域限制的標籤如 imgscript 等,再經過指定回調函數,將響應的內容介接回 JavaScript 中;或是經過 iframe,繞過跨域保護獲取目標資源等。下面僅說明兩種常見也相對正規的解決方式。跨域

CORS

最標準、正確的解決方法是經過 W3C 規範 的「 跨域資源共享(Cross-Origin Resource Sharing ,CORS)」,經過服務器在 HTTP 頭中的設置,能夠使瀏覽器可以獲取不一樣來源的資源。瀏覽器

CORS 規範中,清楚定義了跨域存取控制的運做方式。安全

首先服務器端須要在響應頭中加上如 Access-Control-Allow-OriginAccess-Control-Request-MethodAccess-Control-Request-Headers 等設定,來限制服務器所能接受的來源、請求的方法、可攜帶的頭等等。

當瀏覽器發送資源請求時,若是是簡單請求便會直接送出請求;若不符合前述條件,則會經過預檢(Preflighted)請求先敲敲門,確認是否能夠經過服務器的限制,而後纔會發送正式的請求。

CORS 除了上述內容外,也有關於 Cookies 的傳送方式,如何容許跨域寫入 Cookies 等內容。

代理服務器

因爲 CORS 的頭設置是在服務器端,若是服務器是本身的,那麼能夠輕易的調整服務器設置,讓前端能取得必要的資源;但若是你請求的是外部 API,總不能每次遇到 CORS 錯誤,就要求別人去修改頭設置吧。

簡單暴力的方法就是經過代理服務器幫咱們獲取資源;因爲跨域保護的限制是瀏覽器的規範,只要不經過瀏覽器發送請求,天然也就不會有限制。

常見的做法是經過 nginx 作簡單的反向代理;例如在本身的開發環境,先後端分離的架構,先後端服務分別啓動在 3000 和 5000 端口,則能夠用這樣的配置:

server{
  listen 3000;
  server_name localhost;
  location ^~ /api {
  proxy_pass http://localhost:5000;
  }
}

當前端須要發送 API 請求時,能夠直接請求 localhost:3000/api/...,這個請求會被 nginx 攔截,並轉發給後端所在的 localhost:5000,這樣就能簡單的繞過跨域保護了。

總結

跨域是前端常見的需求,CORS 的錯誤信息也是咱們很容易被卡住的地方;其實只要清楚 CORS 規範中的 HTTP 頭設置,並在服務器端作對應的調整,就能夠順利的完成跨域請求。

173382ede7319973.gif


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索