最近公司佈置了一個公衆號網頁項目,正好有段時間沒用Vue來搭建項目了,想一想仍是從Vue作起,正好如今腳手架也到3.0了,試試鋒利不鋒利。而後就遇到了很多坑。ios
Vue搭建完該請求接口調試,天然是用官方推薦的Axios了,而後就遇到了一個小問題,正常的Post請求,莫名其妙的變爲了OPTIONS請求。npm
平時開發最多見最經常使用的HTTP請求應該是POST和GET。可是HTTP所提供的請求方法卻不止一種。axios
至於這些方法具體的應用,這裏就不作論述了跨域
在代碼中明明是Post的請求,可是在谷歌控制面板中卻顯示的是OPTIONS,這是爲何? 瀏覽器
並且下面還有一段報錯。期初想着多是跨域的問題,而後讓後臺加了響應頭,可是問題並沒解決。後來根據英文提示請求違反CORS協議,去MDN上查詢了什麼事CORS。安全
翻閱MDN關於CORS介紹後(CORS介紹連接),在功能概述中後看到這樣一段話:bash
跨域資源共享標準(CORS:cross-origin sharing standard )新增了一組 HTTP首部字段,容許服務器聲明哪些源站經過瀏覽器有權限訪問哪些資源。另外,規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法(特別是 GET 之外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否容許該跨域請求。服務器確認容許以後,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也能夠通知客戶端,是否須要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。CORS請求失敗會產生錯誤,可是爲了安全,在JavaScript代碼層面是沒法獲知到底具體是哪裏出了問題。你只能查看瀏覽器的控制檯以得知具體是哪裏出現了錯誤。服務器
意思就是對於跨域的請求,除了GET外或者搭配某些 MIME 類型的 POST 請求,都會先發送一次OPTIONS的預請求,用來檢測服務端是否容許該跨域請求。因此對於不符合規範的POST請求就會被擋到外面,因此纔會產生如上的報錯,只發送了OPTIONS請求,而重要的POST沒有發送。app
既然知道問題出在哪裏,那就須要讓發送的請求符合CORS協議。而根據報錯所給的提示 Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. 結合控制面板上面請求頭的信息,發現Access-Control-Allow-Headers的content-type不符合要求,因此纔會觸發CORS檢測。post
既然知道了請求被改變的緣由是由於觸發了CORS檢測,那麼只要符合CORS的規範,規避檢測,就能夠保證成功。在查閱資料後發現有以下內容,可以規避檢測。MDN原文以下(簡單請求):
某些請求不會觸發 CORS 預檢請求。本文稱這樣的請求爲「簡單請求」,請注意,該術語並不屬於 Fetch (其中定義了 CORS)規範。若請求知足全部下述條件,則該請求可視爲「簡單請求」:
請注意上面要求的是知足全部條件。而結合控制面板的信息,以及報錯信息,所發送的信息格式不屬於Content-Type中的任意一種。因此觸發了CORS檢測,致使POST請求不成功。那麼下面只須要使參數的格式是上面Content-Type中所要求的其中一種就能夠了。
而我當時所向後臺傳遞的是一個參數未經處理的Object對象,不屬於上面三種類型中的一種,因此解決方案就是對傳遞的參數進行處理知足要求。
對參數進行字符串轉換
根絕以往的開發經驗,對參數進行JSON.stringify()
處理後,能夠看到請求已經能走通,可是傳遞給後臺的參數,並非後臺想要的。因此這樣做可能須要後臺的配合。 PS:上一家公司就是這樣處理參數的,因此這裏也是驗證猜想,沒想到確實有點用。
能夠看到參數是字符串的形式。
在 axios 中,可使用 URLSearchParams API
var data = new URLSearchParams();
data.append('id', '1');
data.append('name', 'minmin');
data.append('age', '23')
axios.post('url, data).then( res => { ... } ) 複製代碼
可是有一點不方便,若是參數特別多的話,這種方式費事費力,因此仍是用插件解決吧
用插件解決,在項目中引用qs
npm install --save qs
安裝不上的用淘寶鏡像,而後
cnpm install --save qs
複製代碼
//封裝請求方法,全部參數統一用qs.stringify(data)處理
function httpRequest(url, method, data) {
let rdata = { ...publicData, ...data }
rdata = qs.stringify(rdata)
if (method === "post") {
return post(url, rdata)
} else {
return get(url, rdata)
}
}
複製代碼
我的仍是建議在項目中使用插件解決吧,每次經過append參數費時又費力,固然若是公司用的是第一種向後臺傳參,不用插件也沒什麼問題。