需求分析
首先,我们可能需要使用我们封装的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
}