引言
结合业务需求和技术需求,目前使用TS开发小程序,之前已经发过了TypeScript开发微信小程序的环境搭建。虽然现在也有很多第三方开发框架,但是大部分都是基于vue,有一定的学习成本,考虑到技术团队的技术栈统一,所以使用TypeScript进行开发。
在使用前,由于习惯使然自然是利用TS对一些常用操作进行封装,同时也当练手,今天先讲使用TypeScript对微信请求进行封装。
微信请求流程
wx.request({
url: 'www.jianshu.com',
method:'GET'
success(res) {
successCallback(res);
},
fail(fail) {
failCallback(fail);
}
});
可以看出来微信对于请求只给了失败和成功两种状态,每次都需要单独去处理,并且这个success和fail指的是http请求执行的成功失败,并不是我们所期待的接口是否返回正确数据的业务上的成功失败,而我们大多数情况下对于失败的处理都是一致的,而且请求参数很多时候我们也是有固定的。那么接下来我们对这个进行封装。
封装
涉及技术点有:
- 单例
- 链式调用
- TypeScript中interface的使用
- TypeScript中type关键字的使用
- 首先我们把请求需要的东西单独拉出来,包括url,param,header,method,语言组织不好,直接上代码吧。
/**
* http 请求封装
*/
interface HttpRequest {
api: string,
param: any,
needToken?: boolean,
method: HttpMethod
}
/**
* http请求方法枚举
*/
export enum HttpMethod {
GET,
POST
}
- 对于请求的结果使用拦截器进行拦截,在封装中对wx api中的success返回值进行预处理,并进行逻辑判断。
/**
* http请求拦截器
*/
interface HttpInterceptor {
handleResponse(statusCode: number, data: string | IAnyObject | ArrayBuffer, callback: HttpCallback)
}
拦截后我们需要去定义好我们自己业务上的成功失败。
/**
* http请求回调
*/
interface HttpCallback {
/**
* 请求成功
*/
onSuccess: SuccessCallback
onServerError: ErrorCallback
onNetworkError: ErrorCallback
}
/**
* 请求错误
*/
interface HttpError {
code: number,
msg: string
}
/**
* 成功的callback
*/
type SuccessCallback = (data: string | IAnyObject | ArrayBuffer) => void;
/**
* 错误的callback
*/
type ErrorCallback = (error: HttpError) => void;
这样在接口定义上我们就差不多定义好了,接下来就可以把这个网络请求客户端建立起来了。
- 在写HttpClient中我们先准备好一些默认实现,比如拦截器的默认实现和回调的默认处理,因为我们实际上在一个项目中大部分的拦截器逻辑和回调都是一致的。
/**
* 默认的网络拦截器
*/
class DefaultHttpInterceptor implements HttpInterceptor {
private readonly CODE_SUCCESS: number = 200;
public constructor() {
}
handleResponse(statusCode: number, data: string | IAnyObject | ArrayBuffer, callback: HttpCallback) {
let error: ServerError;
if (statusCode == this.CODE_SUCCESS) {
callback.onSuccess(data)
return
}
error = new ServerError(statusCode, data, callback.onServerError)
error.processError();
}
}
export class DefaultCallback implements HttpCallback {
onSuccess: SuccessCallback
onServerError: ErrorCallback
onNetworkError: ErrorCallback
constructor(success: SuccessCallback, serverError?: ErrorCallback, networkError?: ErrorCallback) {
this.onSuccess = success
if (serverError) {
this.onServerError = serverError
} else {
this.onServerError = (error) => {
console.log(error.msg)
}
}
if (networkError) {
this.onNetworkError = networkError
} else {
this.onNetworkError = (error) => {
console.log(error.msg)
}
}
}
}
/**
* 服务器返回错误,如401,500等
*/
class ServerError implements HttpError {
private readonly ERROR_CODE_UNAUTH: number = 401;
private readonly ERROR_CODE_SERVER_ERROR_BASE = 500;
code: number
msg: string
callback: ErrorCallback
constructor(code, msg, callback) {
this.code = code;
this.msg = msg;
this.callback = callback
}
/**
* 网络请求错误处理
* @param callback
*/
processError() {
console.error('get error on http request, error code: ' + this.code + ', error message: ' + this.msg)
if (this.code == this.ERROR_CODE_UNAUTH) {
this.processUnauthError()
} else if (this.code >= this.ERROR_CODE_SERVER_ERROR_BASE) {
this.processServerError()
} else {
this.processUnknownError()
}
}
/**
* 处理未认证错误
*/
processUnauthError() {
}
/**
* 处理服务器返回错误
*/
processServerError() {
}
/**
* 处理未知错误
*/
processUnknownError() {
}
}
- HttpClient
这个客户端我们用单例去实现,这样便于外部使用
/**
* 网络请求客户端
*/
class HttpClient {
private static readonly host: string = 'https://www.jianshu.com/'
private static instance: HttpClient;
private m_Interceptor: HttpInterceptor;
private constructor() {
this.m_Interceptor = new DefaultHttpInterceptor();
}
/**
* 单例
*/
public static getInstance(): HttpClient {
if (!this.instance) {
this.instance = new HttpClient();
}
return this.instance;
}
/**
* 网络请求方法
* @param request 网络请求元素
* @param callback 请求回调
* @param interceptor 自定义拦截器
*/
public request(request: HttpRequest, callback: DefaultCallback, interceptor?: HttpInterceptor) {
wx.request({
url: this.buildUrl(request.api),
data: request.param,
method: request.method == HttpMethod.GET ? "GET" : "POST",
header: this.buildHeader(request.method, request.needToken),
success: (result) => {
// callback.onSuccess(result.data)
if (interceptor) {
interceptor.handleResponse(result.statusCode, result.data, callback)
} else {
this.m_Interceptor.handleResponse(result.statusCode, result.data, callback)
}
},
fail: (reason) => {
if (callback.onNetworkError) {
callback.onNetworkError(new NetworkError(0, reason.errMsg));
}
}
})
}
/**
* 构建header
* @param method
* @param needToken
*/
private buildHeader(method: HttpMethod, needToken = false): IAnyObject {
let contentType: string;
if (method == HttpMethod.GET) {
contentType = ''
} else {
contentType = ''
}
return {
contentType: contentType,
token: needToken ? 'token' : ''
}
}
/**
* 构建url
* @param api
*/
private buildUrl(api: string): string {
return HttpClient.host + api;
}
}
export const ApiClient = HttpClient.getInstance();
写好后,我们在外部使用只需要如下处理
// 网络请求写法1
ApiClient.request({
api: '/test',
method: HttpMethod.GET,
param: null
}, new DefaultCallback((data) => { console.log(data) }))
是不是很方便?
- 当我们有不一样的处理需求时,可以自己去实现接口并传入即可。
语文不好,请各位见谅,欢迎评论交流!
网友评论