前言
最近工作繁忙,继上篇react+typescript构建h5项目已经一个月没有更新内容了。最近有个 h5 的项目正好使用到之前搭建的模板,于是将上述的模板拉过来,配个路由就直接可以使用了,节省不少时间。现在再将 axios 添加到项目中。这项下次再使用到的时候就会更加轻松。
功能
- 常见配置(跨域携带 cookie,token,超时设置,请求头)
- 请求拦截器和响应拦截器
- 请求封装,使用同一套写法
- 请求失败的提示信息
- 支持单个请求的请求或者相应拦截单独处理
开始动手
首先安装 axios npm i axios -S
,引入 axios,添加默认配置,其中基础路径 baseURL,一般是在.env 中拿在 cra 中使用 env,如果是复杂的情况也可以单独建一个文件,通过 window.location.host 在不同环境的区别等等修改 baseURL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import axios, { AxiosRequestConfig, AxiosRequestHeaders, AxiosInstance, AxiosResponse, } from "axios";
import QueryString from "qs"; import { message } from "antd";
interface RequestConfig extends AxiosRequestConfig { headers: AxiosRequestHeaders; } const defaultConfig: RequestConfig = { baseURL: "", timeout: 120 * 1000, withCredentials: true, headers: { "content-type": "application/x-www-form-urlencoded", }, };
|
上面就实现了基础配置的添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const request = ( method: "get" | "post" | "put" | "delete" | "patch" | "head" | "options", url: string, params?: any, config?: AxiosRequestConfig, interceptor?: { request?: any; response?: any; } ): any => { const finalConfig: RequestConfig = { ...defaultConfig, ...config }; const instance: AxiosInstance = axios.create(finalConfig); instance.interceptors.request.use((request) => { return interceptor?.request && typeof interceptor.request === "function" ? interceptor.request(request) : (() => { return request; })(); }); instance.interceptors.response.use( ( response: AxiosResponse<COMMON.ResponseData> ): COMMON.ResponseData | Promise<never> => { if (response.status === 200 && response.data.success) { return interceptor?.response && typeof interceptor.response === "function" ? interceptor.response(response) : (() => { return response.data; })(); } else { message.error(response.data.msg); return Promise.reject(response.data); } }, (error) => { return Promise.reject(error); } );
|
最后是处理请求参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Object.keys(params as object).forEach((item) => { if (item && (params[item] === undefined || params[item] === null)) { delete params[item]; } });
const data = finalConfig.headers["content-type"] === "application/json" ? params : QueryString.stringify(params); const useParams = ["get","delete","head","options"] const useData = ["put","post","patch"] return instance({ method, url, params:useParams.includes(method)&& params, data: useData.includes(method) && data, }); }; export default request;
|
使用
首先呢,现在全局的 types 加上一个规定请求参数和相应参数的泛型
1 2 3 4 5 6 7 8 9 10 11
| interface ResponseData<T = any> { code: number; data: T; msg: string; success: true | false; }
interface REQ<P, T> { (props: P): Promise<ResponseData<T>>; }
|
然后在请求中使用,可以看下面的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| interface RequestProps { username: string; }
interface RecordResponseItem { ... username:string list: any[]; ... }
export const getTestContent: REQ<RequestProps, RecordResponseItem[]> = ( params ) => request( "post", "/xxx", params, { headers: { "content-type": "application/json", }, }, { request: (request: any) => { console.log(request); }, response: (response: any) => { console.log(response); }, } );
|
重点来啦
- 如果这个请求所有的都需要拦截操作可以直接写在这里,如上
- 如果是某次使用需要拦截可以在使用的时候传过来,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { getTestContent } from "@apis";
getTestContent({ username: "liufashi", interceptors: { request: (request: any) => { console.log(request); }, response: (response: any) => { console.log(response); }, }, });
interface RequestProps { username: string; interceptors:any }
|
到此一个相对好用的 axios 已经完成啦!