最近新做了一個專案,因為完全是另起爐灶,可以拋開歷史問題,重新嘗試新的思路與解決方案。也兢兢業業的踩坑倆月,把專案初版跑上線了。這一版主要是保證功能流程沒問題,下一版會對開發流程、效能、錯誤監控等問題進行優化。截至目前記錄的一些問題先抽空整理下。
如題,專案採用vue-cli + es6 + axios
這三個作為基礎跑起來的,依然是移動端,考慮相容性 安卓4.1 & ios7.1
,剛開始引入了jq,後續發現完全沒必要,就引入了axios的ajax庫,然後其他採用原生JavaScript
及ES6
進行開發,也沒遇到什麼大的問題。
Axios
github地址:github.com/axios/axios
在此之前一直用的JQ的$.ajax
,引入axios後還是有一些不一樣的坑要慢慢習慣。
-
請求引數方式不一致
axios中,
get
請求和post
請求攜帶引數的方式不一樣,具體如下:axios.get(url, { params: { id: 123456 } }).then(res => {}) axios.post(url, { id: 123456 }).then(res => {}) 複製程式碼
解決方案是基於axios簡單封了一個
fetch.js
,以簡化、統一呼叫 -
返回值更多資訊
在jq的回撥函式中,我們後端返回的資料直接放在引數中,我們可以直接取res來用,在axios中,回撥函式的引數,包含了更多的資訊:
status:
請求狀態碼statusText:
請求狀態描述headers:
響應頭相關資訊config:
請求的相關配置request:
當次請求相關資訊data:
後端返回的資料 也就是說,在axios的回撥函式中,res.data和$.ajax
回撥函式的res是一致的,而大部分時間,我們只需要知道res.data
而忽略更多資訊,這一點在fetch.js
中也有優化
-
發起一次請求卻抓到兩個請求
兩次請求出現在跨域的前提下,jq中解決跨域問題是通過
jsonp
的方式,而在瀏覽器的標準中,預檢請求是更優雅的解決方案。簡單說,就是在發生跨越的非簡單請求時,瀏覽器會先傳送預檢請求,同服務端確認是否允許接下來的正式請求,如果被允許,則再傳送正式請求。因此我們可能發現我們只傳送了一次post請求,但卻抓到兩次請求,別擔心,這不是bug,是個feature。
-
跨域請求不帶cookie
跨域請求預設不傳送Cookie和HTTP認證資訊。如果要把Cookie發到伺服器,一方面要伺服器同意,指定Access-Control-Allow-Credentials欄位:
Access-Control-Allow-Credentials: true
,另一方面,開發者在發起ajax請求時設定withCredentials為true,這一點也在fetch.js
中做了處理。在這裡,當我們的伺服器設定
Access-Control-Allow-Credentials: true
時,會產生新的問題,在瀏覽器標準中,當伺服器中設定Access-Control-Allow-Credentials
為true時,Access-Control-Allow-Origin
不能設定為*
,而Access-Control-Allow-Origin: *
是我們常用的解決跨域問題的設定。此問題的解決方案有兩種,第一種方案是簡單的設定一個白名單;另一種方案,如果之前設定
Access-Control-Allow-Origin: *
,此時可以在伺服器配置檔案進行設定:先獲取發起跨域請求的源域,然後設定Access-Control-Allow-Origin
的值為獲取到的源域。當然這個設定可能在後端某些配置檔案裡,也可能直接在伺服器配置檔案設定。但思路大概相似。 -
附:fetch.js
簡單封裝,主要就是對上面幾個問題進行了處理。
import axios from 'axios' const fetch = ( url, params = {}, options ) => { let _options = Object.assign({ method: 'get', toastInfo: true, withCredentials: true }, options) let [ _params, _data ] = _options.method === 'get' ? [ params, ''] : [ '', params] return axios({ method: _options.method, url: url, params: _params, data: _data, withCredentials: _options.withCredentials }) .then(res => { let _res = res.data //doSomething return _res }) .catch(e => { //doSomething //錯誤上報 }) } export default fetch 複製程式碼
上面這些問題參考HTTP訪問控制(CORS)大抵都能找到合理解釋。
相容性
- Promise
Promise相容性一般,vue-cli
腳手架中預設沒有對Promise進行pollyfill,在目前的專案中,引用了es6-promise
進行相容處理,大致也就是在不相容的情況下自定義實現一個Promise
- Array.prototype.findIndex
這個屬性在開發過程中多次用到,個人覺得很好用,但相容性也堪憂,就在base.js中新增了pollyfill,pollyfill中還用到了Object.defineProperty
,所以如果vue無法相容的,這個pollyfill也無法相容啦
- Input[type=date]
原生的日期選擇元件用起來不管是在安卓上還是ios上體驗都很棒,但是安卓4.3及以下不識別,此處通過ua判斷了系統版本,安卓4.3以下采用底部彈窗的方式讓使用者輸入日期,犧牲一部分使用者的體驗。
- 開發及部署
這個相關的問題另起一篇吧,此次專案採用的是前端路由加多個單頁應用,後端只提供介面及靜態檔案伺服器,具體開發流程和部署:vue-cli + es6多頁面專案開發及部署。