likes
comments
collection
share

axios-miniprogram-adapter源码解析

作者站长头像
站长
· 阅读数 11

前言

axios-miniprogram-adapter是一个基于axios提供的适配器属性开发的小程序请求适配器,支持多个平台使用,本文主要介绍了它的基本用法以及源码的解析。

注意事项

在小程序中使用axios,其版本仅支持0.26.1及其以下版本。

因为新的版本中引入了form-data包,其所依赖的combined-stream包不支持小程序环境,所以构建后运行会报错。

axios-miniprogram-adapter源码解析

基本用法

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)))