vue-cli + es6 + axios專案踩坑

老李?發表於2018-03-20

最近新做了一個專案,因為完全是另起爐灶,可以拋開歷史問題,重新嘗試新的思路與解決方案。也兢兢業業的踩坑倆月,把專案初版跑上線了。這一版主要是保證功能流程沒問題,下一版會對開發流程、效能、錯誤監控等問題進行優化。截至目前記錄的一些問題先抽空整理下。

如題,專案採用vue-cli + es6 + axios這三個作為基礎跑起來的,依然是移動端,考慮相容性 安卓4.1 & ios7.1,剛開始引入了jq,後續發現完全沒必要,就引入了axios的ajax庫,然後其他採用原生JavaScriptES6進行開發,也沒遇到什麼大的問題。

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多頁面專案開發及部署

相關文章