1. 程式人生 > >一次跨域請求出現 OPTIONS 請求的問題及解決方法

一次跨域請求出現 OPTIONS 請求的問題及解決方法

問題背景
瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、埠、協議任一不同,都是跨域
在前後端開發過程經常會遇到跨域問題。網上也都有解決方案。


寫這篇文章時,我們碰到的一個場景是:要給s系統做一個擴充套件,前端的html、js放在s系統裡,後端需要做一個單獨的站點N.B.com。這就導致了跨域問題,大多數時候 前後端用一個CORS方案 解決跨域問題就可以了。但是我這次有點特別。


前端這邊是一個get請求,按理說也沒啥,但是在請求的header裡面要新增兩個自定義的header


  GET http://localhost:8080/api/v1/users
  Accept: */*
  Content-Type: application/json
  Authorization: token:21232f297a57a5a743894a0e4a801fc3
  Username: admin

增加了兩個自定義欄位 Authorization和Username
在請求時 我看到 network裡面出現了兩次請求記錄 第一次是一個 OPTION請求 狀態碼200第二次是我的get請求 狀態碼 401


可以這邊後端已經做了CORS處理。為何還出現這種情況呢。
我們一般在專案裡解決跨域問題簡單說會採取方案有

  1. 使用ajax直接跨域訪問

2.使用JsonP。實際使用時,由於JsonP向Server提交URL的長度限制在8000字元,超過了則被瀏覽器拒絕,因此不採用。

對於第一種方案,後端需要做的工作是:
介面允許允許跨域請求:


header('Access-Control-Allow-Origin:*');  //支援全域名訪問,不安全,部署後需要限制為R.com
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支援的http動作
header('Access-Control-Allow-Headers:x-requested-with,content-type');  //響應頭 請按照自己需求新增。

前端發起跨域請求:就是正常的$.ajax請求即可。我的專案用的vue全家桶 用的axios 傳送的請求


// request攔截器
service.interceptors.request.use(
  config => {
    if (store.getters.token) {
      config.headers['Authorization'] =`token:${getToken()}` 
      config.headers['Username'] =`getUsername()`
    }
    return config
  },
  error => {
    // Do something with request error
    Promise.reject(error)
  }
)

但是,碰到個問題,國內網站基本沒有講,就是option請求問題。

在正式跨域的請求前,瀏覽器會根據需要,發起一個“PreFlight”(也就是Option請求),用來讓服務端返回允許的方法(如get、post),被跨域訪問的Origin(來源,或者域),還有是否需要Credentials(認證資訊)
三種場景:

  1. 如果跨域的請求是Simple Request(簡單請求 ),則不會觸發“PreFlight”。Mozilla對於簡單請求的要求是:

以下三項必須都成立:

  1. 只能是Get、Head、Post方法
  2. 除了瀏覽器自己在Http頭上加的資訊(如Connection、User-Agent),開發者只能加這幾個:Accept、Accept-Language、Content-Type、。。。。
  3. Content-Type只能取這幾個值:

application/x-www-form-urlencoded
multipart/form-data
text/plain

XHR物件對於HTTP跨域請求有三種:簡單請求、Preflighted 請求、Preflighted 認證請求。簡單請求不需要傳送OPTIONS嗅探請求,但只能按傳送簡單的GET、HEAD或POST請求,且不能自定義HTTP Headers。Preflighted 請求和認證請求,XHR會首先發送一個OPTIONS嗅探請求,然後XHR會根據OPTIONS請求返回的Access-Control-*等頭資訊判斷是否有對指定站點的訪問許可權,並最終決定是否傳送實際請求資訊。
那麼我的get請求呢?
原來,產生 OPTIOINS 請求的原因是:自定義 Headers 頭資訊導致的。
瀏覽器會去向 Server 端傳送一個 OPTIONS 請求,看 Server 返回的 "Access-Control-Allow-Headers" 是否有自定義的 header 欄位。因為我之前沒有返回自定義的欄位,所以,預設是不允許的,造成了客戶端沒辦法拿到資料。

那麼這樣 的話如果後端是python的話


rom corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
    'Authorization,Username'
)

前端這邊如果用的vue全家桶 可以這樣搞一下


module.exports = {
    NODE_ENV: '"development"',
    ENV_CONFIG: '"dev"',
    BASE_API: '"/proxy"'
}


      '/proxy': {
        target: 'http://jupiter.dev.grdoc.org/',
        changeOrigin: true,
        pathRewrite: {
          '^/proxy': '/'
        },
        sesure:false
      }
    

開發環境這樣搞一下 應該就不算跨域了。


我是山豆 我的gitHub