react+typescript 封装 axios

近日在使用react+typescript制作项目,发现ts的使用方法与js的差别相当巨大。其中就包括axios的封装方法,网上找的各种教程也没看懂。于是自己花了将近一天的时间,通过各方面的学习,总算自己封装好了一个ts版的axios。因为之前都是使用vue来开发的,所以这个封装好的axios,我想尽量让它的调用的方式跟原来的vue的调用方式差不多,因为我认为原来的调用方式非常美观且易于管理。

//vue的调用方式
import { request } from './request'

//参数是 地址:url、请求参数:params、仅用于当前api的配置config——该参数选填
export const LoginApi = params => request.post('/user/login', params, {timeout: 15000});

...更多的api

为了达到上面的调用方式,于是自己实现了封装。
以下为详细实现方法:

第一步

安装:axios

// -S 意为该依赖包将会打包至生产环境
cnpm i axios -S

第二步

1、在 src 文件夹下新建 api 文件夹——该文件夹可随意命名,不过推荐使用api来命名
2、在 api 文件夹里新建request.ts文件,下为源码(下面的代码可以直接复制出来使用)

import axios, { AxiosRequestConfig, AxiosRequestHeaders } from 'axios';
import { message } from 'antd'

//基础URL,axios将会自动拼接在url前
//process.env.NODE_ENV 判断是否为开发环境 根据不同环境使用不同的baseURL 方便调试
let baseURL = process.env.NODE_ENV === 'development'? '' : 'https://your.domain.com/api';

//默认请求超时时间
const timeout = 30000;

//创建axios实例
const service = axios.create({
  timeout,
  baseURL,
  //如需要携带cookie 该值需设为true
  withCredentials: true
});

//统一请求拦截 可配置自定义headers 例如 language、token等
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    //配置自定义请求头
    let customHeaders: AxiosRequestHeaders = { 
      language: 'zh-cn' 
    };
    config.headers = customHeaders;
    return config
  },
  error => {
    console.log(error)
    Promise.reject(error)
  }
)

//axios返回格式
interface axiosTypes<T>{
  data: T;
  status: number;
  statusText: string;
}

//后台响应数据格式
//###该接口用于规定后台返回的数据格式,意为必须携带code、msg以及result
//###而result的数据格式 由外部提供。如此即可根据不同需求,定制不同的数据格式
interface responseTypes<T>{
  code: number,
  msg: string,
  result: T
}

//核心处理代码 将返回一个promise 调用then将可获取响应的业务数据
const requestHandler = <T>(method: 'get' | 'post' | 'put' | 'delete', url: string, params: object = {}, config: AxiosRequestConfig = {}): Promise<T> => {
  let response: Promise<axiosTypes<responseTypes<T>>>;
  switch(method){
    case 'get':
      response = service.get(url, {params: { ...params }, ...config});
      break;
    case 'post':
      response = service.post(url, {...params}, {...config});
      break;
    case 'put':
      response = service.put(url, {...params}, {...config});
      break;
    case 'delete':
      response = service.delete(url, {params: { ...params }, ...config});
      break;
  }
  
  return new Promise<T>((resolve, reject) => {
    response.then(res => {
      //业务代码 可根据需求自行处理

      const data = res.data;
      if(data.code !== 200){
        
        //特定状态码 处理特定的需求
        if(data.code == 401){
          message.warn('您的账号已登出或超时,即将登出...');
          console.log('登录异常,执行登出...');
        }

        let e = JSON.stringify(data);
        message.warn(`请求错误:${e}`);
        console.log(`请求错误:${e}`)
        //数据请求错误 使用reject将错误返回
        reject(data);
      }else{
        //数据请求正确 使用resolve将结果返回
        resolve(data.result);
      }

    }).catch(error => {
      let e = JSON.stringify(error);
      message.warn(`网络错误:${e}`);
      console.log(`网络错误:${e}`)
      reject(error);
    })
  })
}

// 使用 request 统一调用,包括封装的get、post、put、delete等方法
const request = {
  get: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('get', url, params, config),
  post: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('post', url, params, config),
  put: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('put', url, params, config),
  delete: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('delete', url, params, config)
};

// 导出至外层,方便统一使用
export { request };

3、新建index.ts文件,导出对应的api

import { request } from './request'

//登录
export const LoginApi = <T>(params: any) => request.post<T>('/user/login', params, {timeout: 15000});

如此一来,就能像vue一样导出和调用了

使用示例

import { LoginApi } from '@/api'

interface loginTypes{
  auth:  Array<string>,
  userInfo: {
    account: string,
    username: string
  },
  token: string
}

LoginApi<loginTypes>(data).then(res => {
  //登录成功。处理区域...
}).catch(err => {
  //登录失败。处理区域...
})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容