最近新开项目,想找一份完整版的ts,封装request完整版都很少,于是最近研究并结合网上的资料进行封装,本api封装支持Promise返回,支持传入泛型,定义返回的数据结构,使用该封装大大减少查看字段及维护难问题。
目录结构
- miniprogram
- api
- index.ts
- base.ts
- system
- userApi.ts
- utils
- request.ts
封装request
首先,我们先搞wx.request先,这个搞完,其它都是小意思,代码如下:<br/>
文件名称request.ts
/**
* @description: HTTP请求方法枚举
*/
export enum HttpMethod {
GET = 'GET',
POST = 'POST',
OPTIONS = 'OPTIONS',
PUT = 'PUT',
DELETE = 'DELETE'
}
/**
* @description: HTTP请求配置
*/
interface RequestConfig {
/** API路径 */
url?: string
/** Method类型 */
method?: HttpMethod
/** 接口返回数据 */
data?: any
/** 无TOKEN触发异常捕获时,是否执行异常逻辑 */
needToken?: boolean
/** Header头部 */
header?: object
/** 返回的数据格式 */
dataType?: string
/** 请求报错时,是否弹出message提示(默认弹出)*/
noShowMsg?: boolean
}
/**
* @description: 声明业务数据类型
*/
export interface MyAwesomeData<T> {
code: number
msg: string
data: T
}
class HttpRequest {
private static instance: HttpRequest
private constructor() { }
/** 请求函数(单例模式)
*
* **注意:**
* `method`需使用`HttpMethod`枚举类,切勿自行定义
*
* **示例代码**
* ```js
HttpRequest.getInstance().request({
url: '/Api',
method: HttpMethod.GET
})
* ```
*/
public static getInstance(): HttpRequest {
if (!this.instance) {
this.instance = new HttpRequest()
}
return this.instance
}
// 处理请求异常状态码
private handerErrorStatus(statusCode: number, requestConfig: RequestConfig) {
let msg = '服务找不到'
if (statusCode === 502 || statusCode === 503) {
msg = '服务器开小差了~'
}
!requestConfig.noShowMsg && wx.showToast({
title: `${msg},错误码:${statusCode}`,
icon: 'none'
})
return msg
}
// 处理请求异常
private handerError(err: { errMsg: string }, requestConfig: RequestConfig) {
let msg = `请求异常`
if (/timeout/.test(err.errMsg)) {
msg = '请求超时'
}
!requestConfig.noShowMsg && wx.showToast({
title: msg,
icon: 'none'
});
return msg
}
// 服务器接口请求
public request<T>(requestConfig: RequestConfig): Promise<MyAwesomeData<T>> {
let _this = this
return new Promise((resolve, reject) => {
// 默认header
const contentType = requestConfig.method === 'GET' ? 'application/x-www-form-urlencoded' : 'application/json'
const header = {
'content-type': contentType
}
wx.request({
method: requestConfig.method,
url: `${requestConfig.url}`,
data: requestConfig.data,
header: Object.assign(header, requestConfig?.header),
dataType: !requestConfig.dataType ? 'json' : '其他',
success: function (res) {
// console.log('发送返回:', res) //res:{cookies, data, header, statusCode}
const code = res.statusCode || -404
const data = res.data
/** 接口请求成功*/
if (code == 200) {
resolve(data as any)
} else if (code === 401) {
// 未授权
!requestConfig.noShowMsg && wx.showModal({
title: '登录失效',
content: '登录失效,请重新登录',
}).then(resModa => {
if (resModa.confirm) { }
})
reject({ code, msg: '未登录', data: data })
} else {
//非200及401状态码-数据处理
const errMsg = _this.handerErrorStatus(code, requestConfig)
reject({ code, msg: errMsg, data })
}
},
fail: err => {
let msg = _this.handerError(err, requestConfig)
reject({ msg })
}
})
})
}
/**
* @description: get请求函数
* @param {string} url 请求地址
* @param {Object} data 请求参数
* @param {RequestConfig} OtherConfig request其他配置
* @return {*}
*/
public get<T>(url: string, data?: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.GET, url, data, ...OtherConfig })
}
/**
* @description: post请求函数
* @param {string} url 请求地址
* @param {Object} data 请求参数
* @param {RequestConfig} OtherConfig request其他配置
* @return {*}
*/
public post<T>(url: string, data: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.POST, url, data, ...OtherConfig })
}
/**
* @description: delete请求函数
* @param {string} url 请求地址
* @param {Object} data 请求参数
* @param {RequestConfig} OtherConfig request其他配置
* @return {*}
*/
public delete<T>(url: string, data: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.DELETE, url, data, ...OtherConfig })
}
/**
* @description: put请求函数
* @param {string} url 请求地址
* @param {Object} data 请求参数
* @param {RequestConfig} OtherConfig request其他配置
* @return {*}
*/
public put<T>(url: string, data?: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.PUT, url, data, ...OtherConfig })
}
}
export const httpRequest = HttpRequest.getInstance()
封装接口api
对接口名称进行封装,文件名称api-> system-> userApi.ts
import { httpRequest } from '../../utils/request'
const baseUrl = require('../base').allBaseUrl.GDEnvs.host
export default class userApi {
/**
* @description: 获取用户信息
* @return {*}
*/
static getUserInfo = (data: UserInfo) =>
httpRequest.post<ReturnUserInfo>(
baseUrl + '/mock/getUserInfo',
data
)
/**
* @description:
* @return {*}
*/
static getVillageList = () =>
httpRequest.get<VillageList>(
baseUrl + '/mock/villageList',
)
}
环境判断封装
对环境进行封装,可自行判断,目录:api-> base.ts
/**
* 获取小程序版本信息
* 值有:develop(开发版)、trial(体验版)、release(正式版)
*/
const accountInfo = wx.getAccountInfoSync()
const envVersion = accountInfo.miniProgram.envVersion || 'release'
/**
* 国地服务器
*/
const GDEnvs = {
develop: {
host: 'https://mock.com',
imgHost: 'http://192.168.0.2:20087'
},
trial: {
host: 'http://192.168.0.1:20086',
imgHost: 'http://192.168.0.2:20086'
},
release: {
host: 'https://XXXXX.com',
imgHost: 'http://image.XXXXX.com'
},
}
export class allBaseUrl {
/**
* 国地服务器
*/
static GDEnvs = GDEnvs[envVersion]
}
接口统一输出
对封装好的api接口统一输出,这个非必要,见仁见智,目录api-> index.ts
/*
* @Author: caiyongqiang
* @Date: 2022-10-20 10:46:54
* @LastEditTime: 2022-10-20 16:58:01
* @LastEditors: caiyongqiang
* @Description:
*/
import userApi from './system/userApi'
class apis {
/**
* @description: 用户相关Api
*/
static userApi = userApi
}
export default apis
页面使用
在页面中可以直接api/index.ts引入使用
import $api from '../../api/index'
// 调用
$api.userApi.getUserInfo({ username: 'demo', password: '123456' }).then((res) => {
if (res.code === 200) {
userStore.setUserInfo(res.data.userInfo)
}
})
TypeError: Cannot read property 'then' of undefined