axios封装new


新版 Axios 封装

import axios, {AxiosRequestConfig, Method} from 'axios';
import {message as AntdMessage} from 'antd';
import _, {debounce} from 'lodash';
import {HEADER, HTTP_REQUEST_URL, TOKEN_NAME, CODE_STATUS} from '@/constants/constants';
import {commonSlice} from '@/store/common';
import store from '@/store/index';
import {getTicketFromUrl, reLogin} from './utils';
export interface RequestConfig {
    token?: boolean;
    message?: boolean;
}
const defaultConfig: RequestConfig = {
    token: true,
    message: true,
};

// const dispatch = useDispatch();

const debouncedShowErrorMessage = debounce((message = '网络连接异常') => AntdMessage.error(message), 500);

const {updateGLoading} = commonSlice.actions;

// 忽略key大小写检查
function checkKeyIgnoreUpCase(target: Record<string, string>, key: string) {
    let res = false;
    if (typeof target !== 'object' || target === null) {
        return res;
    }
    const keys = Object.keys(target);
    res = keys.some(k => {
        return k.toLocaleLowerCase() === key.toLocaleLowerCase();
    });
    return res;
}

// 创建一个 axios 实例
const instance = axios.create({
    baseURL: HTTP_REQUEST_URL, // 公共的接口地址
    timeout: 20000, // 请求超时时间设置
    withCredentials: true, // 跨域时使用凭证,默认带上cookies
});

type InterceptorsConfig = AxiosRequestConfig & {requestConfig: RequestConfig};

// 请求拦截器,config 是发送请求的参数信息
instance.interceptors.request.use(
    config => {
        config.url = `${config.url}`;
        // 是否请求需要带上 token
        if ((config as InterceptorsConfig).requestConfig.token) {
            config.headers[TOKEN_NAME] = localStorage.getItem('ticket') || getTicketFromUrl('ticket');
        }
        store.dispatch(updateGLoading(true));
        return config;
    },
    // 请求拦截的错误回调
    error => {
        store.dispatch(updateGLoading(false));
        return Promise.reject(error);
    }
);

// 响应拦截器,response为响应的结构组织,包括data,headers,status,statusText,config,request
instance.interceptors.response.use(
    response => {
        const shouldMessage = (response.config as InterceptorsConfig).requestConfig.message;
        const {status, message} = response.data;
        // 根据 status 进行判断,与后端约定某些状态该返回什么数据
        switch (status) {
            case CODE_STATUS.SUCCESS:
                store.dispatch(updateGLoading(false));
                return response;

            case CODE_STATUS.FAILED:
                shouldMessage && AntdMessage.error(_.get(response, 'data.message.global', ''));
                store.dispatch(updateGLoading(false));
                break;

            case CODE_STATUS.EXPIRE:
                response.data.result = _.get(response, 'data.result', []);
                store.dispatch(updateGLoading(false));
                shouldMessage && AntdMessage.error('登录凭证失效,请重新登录');
                // setTimeout(()=>{
                //     window.location = SPDB_LOGIN_URL as any;
                // },1000)
                localStorage.removeItem('ticket');
                break;

            default:
                store.dispatch(updateGLoading(false));
                shouldMessage && AntdMessage.error(message);
                return;
        }
        return response;
    },
    // 响应拦截的报错信息,协议报错
    error => {
        if (error && error.response) {
            const status = error.response.status;
            status === 403 && reLogin();
            AntdMessage.error(error.message);
        } else {
            debouncedShowErrorMessage();
        }
        store.dispatch(updateGLoading(false));
        return Promise.reject(error);
    }
);

// 封装 axios 实例
function request(config: AxiosRequestConfig, requestConfig = defaultConfig) {
    const GET_CONTENT_TYPE = 'application/x-www-form-urlencoded;charset=UTF-8';
    const POST_CONTENT_TYPE = 'application/json;charset=utf-8';
    // 获取请求方法
    const method = String.prototype.toUpperCase.call(config.method) || 'GET';
    // 合并headers
    const headers = Object.assign({}, HEADER, config.headers);

    // Content-Type 忽略大小写拼写key是否在对象是已定义
    if (!checkKeyIgnoreUpCase(headers, 'content-type')) {
        if (method === 'GET' || method === 'DELETE') {
            headers['Content-Type'] = GET_CONTENT_TYPE;
        }
        if (method === 'POST' || method === 'PUT') {
            headers['Content-Type'] = POST_CONTENT_TYPE;
        }
    }
    // 给config上面绑定字段,方便在拦截器中使用
    (config as any).requestConfig = Object.assign(defaultConfig, requestConfig);
    return instance(config).then(res => res.data);
}

const requestMethod: Method[] = ['options', 'get', 'post', 'put', 'head', 'delete'];

export type AjaxFunc = <T = any, K = any>(
    url: string,
    data?: T,
    requestConfig?: RequestConfig,
    options?: AxiosRequestConfig
) => Promise<K>;

// 导出一个更简便的方法
export function fetch<T = any, K = any>(
    url: string,
    method: Method = 'GET',
    data?: T,
    requestConfig = defaultConfig,
    extraConfig?: AxiosRequestConfig
): Promise<K> {
    // 获取请求类型
    const casedMethod = method.toUpperCase() as Method;
    const config = {
        url,
        method: casedMethod,
    } as AxiosRequestConfig;
    // data处理,get和post的data传输不一样
    if (casedMethod === 'GET') {
        config.params = data;
    } else {
        config.data = data;
    }
    return request({...extraConfig, ...config}, requestConfig);
}

// ajax.get()/ajax.post()等等类似这样调用
const ajax = {} as {
    [k in Method]: AjaxFunc;
};
requestMethod.forEach(method => {
    ajax[method] = <T, K>(api: string, data: T, requestConfig = defaultConfig, opt?: AxiosRequestConfig) =>
        fetch<T, K>(api, method, data, requestConfig, opt || {});
});

// 导出
export default ajax;
// 使用

import ajax from '@/utils/request';

import capi from './api';

// example

export const getDataSource = async () => {
    const result = await ajax.get(capi.sourceData);
    return result.data;
};

export const getDataList = async (params: any) => {
    const result = await ajax.post(capi.dataList, params);
    return result.data;
};

文章作者: KarlFranz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 reprint policy. If reproduced, please indicate source KarlFranz !
评论
  目录