【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
}
posted @ 2019-08-20 22:45  林璡  阅读(1695)  评论(0编辑  收藏  举报