typescript 配置 axios

7,626 阅读2分钟

以vue项目为例,介绍ts版配置axios的问题。

./package.json 中用到了axios。UI随意,这里用了element-plus

{
  ...
  "dependencies": {
    ...
    "element-plus": "^1.0.1-beta.21",
    ...
    "axios": "^0.21.1",
    ...
  },
  ...
}

新增 /src/api/request.ts 文件。

import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios';
import { ElMessage } from 'element-plus'
 
export class Request {
    public static axiosInstance: AxiosInstance;

    // constructor() {
    //     // 创建axios实例
    //     this.axiosInstance = axios.create({timeout: 1000 * 12});
    //     // 初始化拦截器
    //     this.initInterceptors();
    // }

    public static init() {
        // 创建axios实例
        this.axiosInstance = axios.create({
            baseURL: process.env.VUE_APP_BASE_URL + '/api/v1',
            timeout: 6000
        });
        // 初始化拦截器
        this.initInterceptors();
        // return axios;
    }

    // 为了让http.ts中获取初始化好的axios实例
    // public getInterceptors() {
    //     return this.axiosInstance;
    // }

    // 初始化拦截器
    public static initInterceptors() {
        // 设置post请求头
        this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        /**
         * 请求拦截器
         * 每次请求前,如果存在token则在请求头中携带token
         */
        this.axiosInstance.interceptors.request.use(
            (config: AxiosRequestConfig) => {
 
                // const token = Vue.ls.get(ACCESS_TOKEN)
                // if (token) {
                //     config.headers['Authorization'] = 'Bearer ' + token
                // }
 
                // 登录流程控制中,根据本地是否存在token判断用户的登录情况
                // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
                // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
                // if (config.headers.isJwt) {
                    const token = localStorage.getItem('ACCESS_TOKEN');
                    if (token) {
                        config.headers.Authorization = 'Bearer ' + token;
                    }
                // }
                return config;
            },
            (error: any) => {
                console.log(error);
            },
        );
 

        // 响应拦截器
        this.axiosInstance.interceptors.response.use(
            // 请求成功
            (response: AxiosResponse) => {
                // if (res.headers.authorization) {
                //     localStorage.setItem('id_token', res.headers.authorization);
                // } else {
                //     if (res.data && res.data.token) {
                //         localStorage.setItem('id_token', res.data.token);
                //     }
                // }
 
                if (response.status === 200) {
                    // return Promise.resolve(response.data);
                    return response;
                } else {
                    Request.errorHandle(response);
                    // return Promise.reject(response.data);
                    return response;
                }
            },
            // 请求失败
            (error: any) => {
                const {response} = error;
                if (response) {
                    // 请求已发出,但是不在2xx的范围
                    Request.errorHandle(response);
                    return Promise.reject(response.data);
                } else {
                    // 处理断网的情况
                    // eg:请求超时或断网时,更新state的network状态
                    // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
                    // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
                    ElMessage.warning('网络连接异常,请稍后再试!');
                }
            }
        );
    }

    /**
     * http握手错误
     * @param res 响应回调,根据不同响应进行不同操作
     */
    private static errorHandle(res: any) {
        // 状态码判断
        switch (res.status) {
            case 401:
                break;
            case 403:
                break;
            case 404:
                ElMessage.warning('请求的资源不存在');
                break;
            default:
                ElMessage.warning('连接错误');
        }
    }

}
  • request.ts 封装了 Request 方法,使用 class 语法糖,过程中创建了axiosInstance
  • 因为使用了ts版,从axios依赖中引用了AxiosInstanceAxiosRequestConfigAxiosResponse, 这三个属于接口interface
  • Request类实现中包含创建实例this.axiosInstance,初始化拦截器,拦截器中包括响应拦截和请求拦截。请求拦截设置了 token ,响应拦截处理了错误逻辑。
  • baseURL 中的process.env.VUE_APP_BASE_URL 是通过.env.development 配置得到的。

.env.development

NODE_ENV = 'development'
VUE_APP_BASE_URL='http://0.0.0.0:8899'

对应 ./package.json 中的脚本

{
  ...
  "scripts": {
    "serve": "vue-cli-service serve --mode development",
    "build": "vue-cli-service build --mode production"
  },
  ...
}

/src/main.ts 中引入了刚创建的request.ts

...
import { Request } from '@/api/request';
const app = createApp(App as any)
Request.init();
...

新增 /src/api/api.ts 文件,随意创建一个 login 的接口进行测试。

import { Request } from './request';
export function login (parameter: any)  {
  return Request.axiosInstance({
    url: '/login',
    method: 'post',
    data: parameter
  })
}

用随便一个页面,比如 /src/views/Home.vue 中

import { defineComponent, onMounted } from 'vue';
import { login } from '@/api/api';
export default defineComponent({
  name: 'Home',
  setup() {
  	onMounted(()=>{
      login({
        username:'admin',
        password:'123456'
  	  });
  	})
  }
});
  • Composition API
  • 引入刚写的 login 接口
  • onMounted方法中调用 login
  • 可以通过nodejs创建一个 login 接口测试。