评论

小程序TypeScript请求封装(TS+request),拿来就能用

顺应时代的进步,TS似乎已经是一个不断突破的大方向,无法阻挡,那我们就逆来顺受,好好干它吧~

最近新开项目,想找一份完整版的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)
    }
})
最后一次编辑于  2022-11-11  
点赞 4
收藏
评论

1 个评论

  • 。
    11-05

    TypeError: Cannot read property 'then' of undefined

    11-05
    赞同
    回复
登录 后发表内容