【Ts重構Axios】url處理篇


需求分析

首先,我們可能需要使用我們封裝的axios去發送一個下面這樣的簡單請求

axios({
    method: 'get',
    url: '/api/getInfo',
    params: {
        a: 1,
        b: 2
    }
})

最終,我們希望我們發送的請求url是這樣的,/api/getInfo?a=1&b=2,這樣服務器就可以通過請求的url解析到我們傳來的參數了。那么,我們要做的實際上就是把params的key和vaule拼接到url上,當然,params是很負責的,可能會有以下幾種情況:

參數為數組

axios({
    method: 'get',
    url: '/api/getiInfo',
    params: {
        foo: ['bar', 'baz']
    }
})

最終請求的url是這樣的:/api/getInfo?foo[]=bar&foo[]=baz

參數為對象

axios({
    method: 'get',
    url: '/api/getiInfo',
    params: {
        foo: {
            bar: 'baz'
        }
    }
})

最終請求的url是這樣的: /api/getInfo?foo=%7b%22bar:%22baz%2z%7d,foo后面拼接的是{"bar": "baz"}encode后的結果

參數為Date對象

axios({
    method: 'get',
    url: '/api/getiInfo',
    params: {
        date
    }
})

最終請求的url是/api/getInfo?date=2019-04-01T05:55:39.030Z,date后面跟的是date.toISOString()的結果

特殊字符的支持

對於@、:、$、[、]、空格,我們是允許出現在url中的,不希望encode

axios({
    method: 'get',
    url: '/api/getiInfo',
    params: {
        foo: '@:$'
    }
})

最終請求的url是這樣的:/api/getInfo?foo=@:$+,注意我們會把空格轉換成+

空值忽略

對於值為null或者undefined的屬性,我們是不會添加到url參數中的。

axios({
    method: 'get',
    url: '/api/getiInfo',
    params: {
        foo: 'bar',
        baz: null
    }
})

最終請求的url是:/api/getInfo?foo=bar

丟棄url中的哈希標記

axios({
    method: 'get',
    url: '/api/getInfo#hash',
    params: {
        foo: 'bar'
    }
})

最終請求的url是:/api/getInfo?foo=bar

保留url中已存在的參數

axios({
    method: 'get',
    url: '/api/getiInfo?foo=bar',
    params: {
        bar: 'baz'
    }
})

最終請求的url是:/api/getInfo?foo=bar&bar=baz

buildUrl的實現

根據上面我們的分析,接下來我們來實現一個工具function,然后把params拼接到url上,並能處理上面這幾種params

// helpers/util.ts
const toString = Object.prototype.toString

export function isDate(val: any): val is Date {
    return toString.call(val) === '[object Date]'
}

export function isObject(val: any): val is Object {
    return val !== null && typeof val === 'object'
}

export function isPlainObject(val: any): val is Object {
    return toString.call(val) === '[object object]'
}

// helpers/url.ts

import { isDate, isPlainObject } from './util'
import { encode } from 'punycode';


export function buildUrl(url: string, params?: any): string {
    if (!params) {
        return url
    }

    const parts: string[] = []

    Object.keys(params).forEach(key => {
        const val = params[key]
        if (val === null || typeof val === 'undefined') {
            return // 結束本次forEach
        }

        let values = []
        if (Array.isArray(val)) {
            values = val
            key += '[]'
        } else {
            values = [key]
        }
        values.forEach(val => {
            if (isDate(val)) {
                val = val.toISOString()
            } else if (isPlainObject(val)) { // 普通對象,不包含formData類型等
                val = JSON.stringify(val)
            }
            parts.push(`${encode(key)}=${encode(val)}`)
        })
    })

    let serialzedParams = parts.join('&')

    if (serialzedParams) {
        const markIndex = url.indexOf('#')
        if (markIndex !== -1) {
            url = url.slice(markIndex, 1)
        }
        url += (url.indexOf('?') === -1 ? '?' : '&')
    }

    return url
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM