大家好,我是Aliom252181,一個佛系且資質(zhì)平平的前端coder,今天分享下我是如何使用Typescript
封裝wx.request
的。
寫在前面
本篇文章適合有封裝TS版本小程序請求需求的coder,通過本篇閱讀,你將會了解到:
- TS代碼提示;
- 單例模式;
- 每個接口都可以靈活配置請求頭、超時時間等;
- 取消原生嵌套地獄寫法,更符合閱讀邏輯。
微信小程序自帶的wx.request
請求方式使用方式如下:
wx.request({
url: 'http://host/api/key', //請求的接口地址
method:"get", //http請求數(shù)據(jù)的方式
data:{name:'',age:''}, //請求的參數(shù),如name和id
//請求頭設(shè)置,根據(jù)需要自己設(shè)置
header:{
'content-type':"application/json"
},
//請求成功時的回調(diào)函數(shù)
success(res){
console.log(res);
},
//請求失敗的回調(diào)函數(shù)
fail(msg){
console.log(msg);
}
})
如果不封裝的話,每次使用請求都會造成大段重復(fù)代碼占用代碼區(qū),對閱讀極其不利,也降低了開發(fā)效率,為了解決這個問題,一起來開啟封裝之旅吧。
基礎(chǔ)類型封裝
首先我們要先定義一些我們需要的類型,例如請求參數(shù)類型,返回數(shù)據(jù)類型,還有一些枚舉類型,現(xiàn)在開始封裝:
封裝HTTP請求配置
// HTTP請求方法枚舉
export enum HttpMethod {
GET,
POST
}
// HTTP請求配置
interface RequestConfig {
/** API路徑 */
url?: string
/** Method類型 */
method?: HttpMethod
/** 接口返回數(shù)據(jù) */
data?: any
/** 無TOKEN觸發(fā)異常捕獲時,是否執(zhí)行異常邏輯 */
needToken?: boolean
/** Header頭部 */
header?: object
}
其中needToken
是我們的業(yè)務(wù)邏輯,此參數(shù)主要作用于一些需要權(quán)限接口,如果我們不想讓他在request
層級觸發(fā)我們的邏輯,例如不想觸發(fā)登錄驗證,就可以在接下來處理返回code時使用。
封裝請求返回數(shù)據(jù)類型
// 繼承中間類型,data聲明為any
interface AnyResult extends WechatMiniprogram.RequestSuccessCallbackResult {
data: any
}
// 從中間類型繼承一個泛型接口,data聲明為泛型
interface SpecResult<T> extends AnyResult {
data: T
}
// 聲明業(yè)務(wù)數(shù)據(jù)類型
export interface MyAwesomeData {
code: number
msg: string
data: any
}
這一步是定義返回參的類型,我們希望最終的返回結(jié)果為{code,msg,data}
,便于我們的使用。其中注意WechatMiniprogram
是微信提供的類型,需要大家在TS小程序項目內(nèi)使用,也可以使用NPM包miniprogram-api-typings
來作為校驗,如果是后者,要注意在tsconfig.json
的typeRoots
字段內(nèi)設(shè)置此包地址,例如:
"typeRoots": [
"./node_modules/miniprogram-api-typings"
],
環(huán)境配置
除了正式環(huán)境,大家的日常開發(fā)中免不了要進行多環(huán)境切換,這里寫成配置,方便開發(fā)使用。
首先新建env.ts文件作為環(huán)境配置中心,這里我已常用的三環(huán)境為例,大家自行擴展。
// env.ts
let envs = {
dev: {
host: 'http://192.168.0.1:20087/',
imgHost: 'http://192.168.0.2:20087/'
},
test:{
host: 'http://192.168.0.1:20086/',
imgHost: 'http://192.168.0.2:20086/'
},
prod: {
host: 'https://XXXXX.com/',
imgHost: 'http://image.XXXXX.com/'
},
}
module.exports = envs
接下來新建config.ts文件作為小程序配置中心,用來控制環(huán)境切換和其他配置。
// config.ts
// 基礎(chǔ)共同的配置
let baseConfig = {
// 小程序appid
appid: '……',
// 環(huán)境
ENV:'dev'
}
//環(huán)境文件
let envConfig = require('./env')
// 合并配置
let config = Object.assign(baseConfig, envConfig[baseConfig.ENV])
// 導(dǎo)出配置
module.exports = config
核心代碼封裝
恭喜你,看到這里,你已經(jīng)完成了所有封裝的前期準備工作,那么我們開始正式封裝。
定義核心請求類HttpRequest
這里我們使用單例模式定義此核心類,好處有三:
- 單例模式可以確保所有對象都訪問唯一實例;
- 因為類控制了實例化過程,所以類可以靈活更改實例化過程;
- 因為只有一個實例,所以減少內(nèi)存開支和系統(tǒng)的性能開銷。
雖然我很贊同那句:最好的注釋就是沒有注釋",但是這在工具類里顯然不生效,工具類的作用是讓使用的人快速完成某項活動,而不是讓他驚嘆三連。所以該有的注釋還是要有的,如果大家對于注釋感興趣的人數(shù)足夠多,我會開一期如何寫注釋的文章。
export class HttpRequest {
private static instance: HttpRequest
private constructor() {}
/** 請求函數(shù)(單例模式)
*
* **注意:**
* 1. 處理請求的函數(shù)記得使用`async/await`
* 2. `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
}
}
寫到這里,單例模式就完成了,那么現(xiàn)在我們需要實現(xiàn)url的拼接。
處理url
在HttpRequest
中定義getApiAppName
方法。此方法是兼容全路徑寫法的請求,在實際開發(fā)中,可以有一些非環(huán)境配置中心的請求需要處理,所以這里做一個兼容處理,同時也拼接好了全路徑。
// 處理url 兼容全路徑
private getApiAppName(url: string | undefined) {
if (!url) {
return
}
if (typeof url == 'string' && url.indexOf('http') >= 0) {
return url
}
return `${Config.host}${url}`
}
處理異常
在HttpRequest
中定義handerErrorStatus
方法。此方法是用來處理后端異常狀態(tài)碼。
// 處理后端異常狀態(tài)碼
private handerErrorStatus(statusCode: number, requestConfig: RequestConfig) {
if (statusCode == 502 || statusCode == 503) {
if (requestConfig.needToken) {
wx.showToast({
title: '服務(wù)器開小差',
icon: 'none'
})
}
return true
}
return false
}
定義核心方法request
在HttpRequest
中引入配置文件。
// 引入配置文件
const Config = require('../config/config')
接下來在HttpRequest
中定義核心方法request
,這里在處理狀態(tài)碼的時候采用的是if/else
寫法,如果大家業(yè)務(wù)里有更多的邏輯可以外面把規(guī)則定義成Map
,然后內(nèi)部引用規(guī)則,方便理解和閱讀。
再次強調(diào),一個好的代碼是可以別人看懂而不是只有自己能看到,尤其是工具類方法,更要要降低理解門檻和使用門檻。
public request(requestConfig: RequestConfig): Promise<SpecResult<MyAwesomeData>> {
let _this = this
//url處理
requestConfig.url = this.getApiAppName(requestConfig.url)
return new Promise((resolve, reject) => {
// 默認header
let header = {
'content-type': 'application/json'
}
wx.request({
method: requestConfig.method === HttpMethod.GET ? 'GET' : 'POST',
url: `${requestConfig.url}`,
data: requestConfig.data,
header: Object.assign(header, requestConfig?.header),
success: async function (res: SpecResult<MyAwesomeData>) {
console.log('發(fā)送返回:', res) //res:{cookies, data, header, statusCode}
if (_this.handerErrorStatus(res.statusCode, requestConfig)) {
reject('失敗了')
} else {
// 200狀態(tài)碼請求正常
if (res.statusCode == 200) {
if ([401, 402, 403, 405, 407, 408].indexOf(res.data.code) != -1 && requestConfig.needToken) {
//……
}
} else {
//非200狀態(tài)碼(排除handerErrorStatus特殊處理過的狀態(tài)碼)-數(shù)據(jù)處理
res.data = { code: res.statusCode || -404, msg: '服務(wù)找不到', data:res.data }
}
}
resolve(res)
},
fail: err => reject(err)
})
})
}
恭喜你,到這里,封裝已經(jīng)完美結(jié)束了,那么我們一起來看下如何使用吧。
使用
- 在需要使用的文件內(nèi)引入
request
。
import { HttpMethod, HttpRequest } from '/resources/utils/request';
- 使用
async/await
接受返回值。
const res = await HttpRequest.getInstance().request({
url: 'serviceProduct/showcase/getShowcase',
method: HttpMethod.GET
})
- 可以開始業(yè)務(wù)邏輯啦!
寫在最后
小程序這個系列我還會繼續(xù)更新,敬請期待~文章來源:http://www.zghlxwxcb.cn/news/detail-491455.html
本篇文章到這里就結(jié)束了,如果文章對你有用,可以三連支持一下,如果文章中有錯誤或者說你有更好的見解,歡迎指正~文章來源地址http://www.zghlxwxcb.cn/news/detail-491455.html
到了這里,關(guān)于小程序開發(fā)指南-TS封裝wx.request的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!