axios-miniprogram-adapter源码解析
前言
axios-miniprogram-adapter是一个基于axios提供的适配器属性开发的小程序请求适配器,支持多个平台使用,本文主要介绍了它的基本用法以及源码的解析。
注意事项
在小程序中使用axios,其版本仅支持0.26.1及其以下版本。
因为新的版本中引入了form-data包,其所依赖的combined-stream包不支持小程序环境,所以构建后运行会报错。
基本用法
1.初始化
可根据实际项目需求进行二次定制
// http.js
import axios from 'axios'
import wxAdapter from 'axios-miniprogram-adapter'
axios.defaults.adapter = wxAdapter
const http = axios.create({
baseURL: 'http://localhost:8099'
})
export default http
2.页面中使用
同axios使用
import http from '../../utils/http'
Page({
onLoad () {
this.getUserInfo()
},
async getUserInfo () {
try {
const res = await http.get('/user', { id: 1 })
console.log(res)
} catch (error) {
console.error(error)
}
}
})
源码解析
- 1.源码入口 axios-miniprogram-adapter/src/index.ts
- 2.通过getRequest方法根据不同的平台返回不同的请求实例(这里只讨论微信小程序的)
- 3.mpAdapter函数返回 AxiosAdapter类型
// 源码位置 axios\index.d.ts
export interface AxiosAdapter {
(config: InternalAxiosRequestConfig): AxiosPromise;
}
1.初始化request请求参数
const mpRequestOption: WechatMiniprogram.RequestOption = {
// 传入请求参数
method: requestMethod as | 'OPTIONS'
| 'GET'
| 'HEAD'
| 'POST'
| 'PUT'
| 'DELETE'
| 'TRACE'
| 'CONNECT',
// 构建完整的url
url: buildURL(buildFullPath(config.baseURL, config.url), config.params, config.paramsSerializer),
// 设置超时时间
timeout: config.timeout,
// Listen for success
// 请求成功
success: (mpResponse: any) => {
// 生成axios类型的response
const response = transformResponse(mpResponse, config, mpRequestOption)
settle(resolve, reject, response)
},
// Handle request Exception
// 请求失败
fail: (error) => {
transformError(error, reject, config)
},
// 请求完成
complete () {
// 清除请求任务对象
requestTask = undefined
}
}
1.buildFullPath(config.baseURL, config.url)
通过baseURL与传入的url构建完整的请求url
比如上文中的http.get('/user'),构建后的完整路径为http://localhost:8099/user
2.buildURL(fullPath, config.params, config.paramsSerializer)
通过buildURL与传入的params构建查询字符串
比如上文中的http.get('/user', { id: 1 }),构建后的完整路径为http://localhost:8099/user?id=1
paramsSerializer为params的序列化函数
3.transformResponse
将返回的结果格式化为AxiosResponse类型
// 源码位置 axios\index.d.ts
interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: AxiosResponseHeaders;
config: AxiosRequestConfig<D>;
request?: any;
}
4.settle
根据返回的response执行resolve或者reject
// 源码位置 axios\lib\core\settle.js
function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response)
} else {
reject(createError(
'Request failed with status code ' + response.status,
response.config,
null,
response.request,
response
))
}
}
2.增加授权
同axios,如果设置了auth属性,则在header中增加Authorization属性,并对传入的username和password执行base64编码。
// HTTP basic authentication
if (config.auth) {
const [username, password] = [config.auth.username || '', config.auth.password || '']
requestHeaders.Authorization = 'Basic ' + encode(username + ':' + password)
}
3.设置请求头
设置请求头,如果未传入data,则删除content-type,如果传入了referer属性,则直接删除(小程序禁止传入referer)。
// Add headers to the request
utils.forEach(requestHeaders, function setRequestHeader (val: any, key: string) {
const _header = key.toLowerCase()
if ((typeof requestData === 'undefined' && _header === 'content-type') || _header === 'referer') {
// Remove Content-Type if data is undefined
// And the miniprogram document said that '设置请求的 header,header 中不能设置 Referer'
delete requestHeaders[key]
}
})
mpRequestOption.header = requestHeaders
4.监听请求取消
监听请求取消,调用abort函数,中止请求。
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled (cancel) {
if (!requestTask) {
return
}
requestTask.abort()
reject(cancel)
// Clean up request
requestTask = undefined
})
}
5.执行请求
// Converting JSON strings to objects is handed over to the MiniPrograme
if (isJSONstr(requestData)) {
requestData = JSON.parse(requestData)
}
if (requestData !== undefined) {
mpRequestOption.data = requestData
}
requestTask = request(transformRequestOption(transformConfig(mpRequestOption)))