我们通常开始直接在代码中使用像axios这样的第三方库。这没有错。但是,在不断变化的库,软件包,版本等世界中,直接使用这些库API可能会导致代码不一致。
一个好的做法是创建自己的抽象并将对库API的调用包装到包装器中。这将使您保持代码更加一致,并且在将来需要时也可以更轻松地切换到其他库或者程序包。这是因为您将所有对第三方库的调用都包装在一个位置,并且只要包装器接口没有更改,就可以替换包装器方法的实现以切换到新库。
让我们开始写代码
在用于发出Http请求的代码的特定情况下,我们可以创建一个名为IHttpClient的接口,然后创建一个名为HttpClient的类来实现该接口。在我们的HttpClient方法中,我们将调用axios方法。
现在,让我们假设HttpClient仅具有通用的get和post方法:
export interface IHttpClient {get<T>(parameters: IHttpClientRequestParameters): Promise<T>post<T>(parameters: IHttpClientRequestParameters): Promise<T>
}
我们还需要一个接口,以将我们的参数传递给带有一个参数的get和post,以避免代码混乱。我们将其称为IHttpClientRequestParameters,它将花费一些通用时间T来定义传入的有效负载的类型(如果有)以及用于任何类型的Http请求的其他通用参数:
export interface IHttpClientRequestParameters<T> {url: stringrequiresToken: booleanpayload?: T
}
这是请求参数接口的每个属性的详细说明:
url:这是我们需要向其发出请求的API端点的完整url(必须包含查询字符串参数)
requireToken:这是一个布尔值,指示我们的请求是否还必须添加身份验证令牌(即Jwt令牌)
有效负载:这是POST或PUT请求的有效负载,因此是可选的。现在,我们可以编码HttpClient类,以实现IHttpClient接口并使用axios。首先,从axios导入所需的内容,并编写尚未实现的HttpClient类的初始声明:
import axios, { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios'export class HttpClient implements IHttpClient {// ... implementation code will go here
}
现在,按照界面中的定义添加get方法的实现。请注意,这里我使用的是Promise语法,但是欢迎您使用async / await语法。我们的get方法将使用IHttpClientRequestParameters的实例并返回Promise:
get<T>(parameters: IHttpClientRequestParameters): Promise<T> {return new Promise<T>((resolve, reject) => {// extract the individual parametersconst { url, requiresToken } = parameters // axios request options like headers etcconst options: AxiosRequestConfig = {headers: {}}// if API endpoint requires a token, we'll need to add a way to add this.if (requiresToken) {const token = this.getToken()options.headers.RequestVerificationToken = token}// finally execute the GET request with axios:axios.get(url, options).then((response: any) => {resolve(response.data as T)}).catch((response: any) => {reject(response)})})
}
同样,现在添加接口中定义的post方法的实现。像get一样,我们的post方法将采用IHttpClientRequestParameters的实例并返回Promise:
post<T>(parameters: IHttpClientRequestParameters): Promise<T> {return new Promise<T>((resolve, reject) => {const { url, payload, requiresToken } = parameters// axios request options like headers etcconst options: AxiosRequestConfig = {headers: {}}// if API endpoint requires a token, we'll need to add a way to add this.if (requiresToken) {const token = this.getToken()options.headers.RequestVerificationToken = token}// finally execute the GET request with axios:axios.post(url, payload, options).then((response: any) => {resolve(response.data as T)}).catch((response: any) => {reject(response)})})
}
现在,您可以导出HttpClient的实例并在整个代码中使用:
export const httpClient = new HttpClient()
这是一个示例,我们使用它来获取IItem类型的“项目”列表:
fetchItems(): Promise<IItem[]> {// prepare our request parametersconst getParameters: IHttpClientPostParameters = {url: 'http://yourapiurl/items',requiresToken: false}// just return httpClient.get (which is a promise) or again use async/await if you preferreturn httpClient.get<IItem[]>(getParameters)
}
总结
现在,您有了一个HttpClient,它抽象了不同的Http请求(如get或post等)并将代码封装在一个地方。在HttpClient中,您可以使用axios或者其他平台的请求库亦或其他请求协议,这样并不会污染你外部的代码。