axios基础功能实现
请求url参数
axios({
method: 'get',
url: '/base/get',
params: {
a: 1,
b: 2
}
})
希望的最终url是/base/get?a=1&b=2。实际上就是把 params 对象的 key 和 value 拼接到 url 上。下面是几种复杂的情况的处理:
-
参数值为数组 foo: ['bar', 'baz']
最终请求的 url 是 /base/get?foo[]=bar&foo[]=baz'
-
参数值是对象foo: { bar: 'baz' }
最终请求的 url 是 /base/get?foo=%7B%22bar%22:%22baz%22%7D,foo 后面拼接的是 {"bar":"baz"} encode 后的结果
-
参数值是Date
最终请求的 url 是 /base/get?date=2020-07-17 T05:55:39.030Z,date 后面拼接的是 date.toISOString() 的结果
-
特殊字符
对于字符 @、:、$、,、、[、],我们是允许出现在 url 中的,不希望被 encode。空格会转变为" + "
-
空值忽略
对于值为 null 或者 undefined 的属性,我们是不会添加到 url 参数中的
-
丢弃 url 中的哈希标记
-
保留 url 中已存在的参数
实现一个工具函数把 params 拼接到 url 上
function encode (val: string): string {
return encodeURIComponent(val)
.replace(/%40/g, '@')
.replace(/%3A/gi, ':')
.replace(/%24/g, '$')
.replace(/%2C/gi, ',')
.replace(/%20/g, '+')
.replace(/%5B/gi, '[')
.replace(/%5D/gi, ']')
}
export function bulidURL (url: string, params?: any) {
if (!params) {
return url
}
const parts: string[] = []
Object.keys(params).forEach((key) => {
let val = params[key]
if (val === null || typeof val === 'undefined') {
return
}
let values: string[]
if (Array.isArray(val)) {
values = val
key += '[]'
} else {
values = [val]
}
values.forEach((val) => {
if (isDate(val)) {
val = val.toISOString()
} else if (isObject(val)) {
val = JSON.stringify(val)
}
parts.push(`${encode(key)}=${encode(val)}`)
})
})
let serializedParams = parts.join('&')
if (serializedParams) {
const markIndex = url.indexOf('#')
if (markIndex !== -1) {
url = url.slice(0, markIndex)
}
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
}
return url
}
请求body数据
我们通过执行 XMLHttpRequest 对象实例的 send 方法来发送请求,并通过该方法的参数设置请求 body 数据
当我们传一个普通对象给服务端的时候,data不能直接传给send函数,需要把它转化为JSON字符串
请求header
我们做了请求数据的处理,把 data 转换成了 JSON 字符串,但是数据发送到服务端的时候,服务端并不能正常解析我们发送的数据,因为我们并没有给请求 header 设置正确的 Content-Type。
所以我们首先要支持发送请求的时候可以配置headers
function normalizeHeaderName (headers: any, normalizedName: string): void {
if (!headers) {
return
}
Object.keys(headers).forEach(name => {
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
headers[normalizedName] = headers[name]
delete headers[name]
}
})
}
export function processHeaders (headers: any, data: any): any {
normalizeHeaderName(headers, 'Content-Type')
if (isPlainObject(data)) {
if (headers && !headers['Content-Type']) {
headers['Content-Type'] = 'application/json;charset=utf-8'
}
}
return headers
}
这里因为请求header属性是不分大小写的,所以需要事先规范化