feat(service): 完善axios的网络错误处理

This commit is contained in:
Coffee-crocodile 2023-01-11 18:16:54 +08:00
parent 6ef49cb047
commit 204cb7ad9f
5 changed files with 222 additions and 160 deletions

View File

@ -1 +1,2 @@
export * from './sdk';
export * from './service';

34
src/config/service.ts Normal file
View File

@ -0,0 +1,34 @@
/** 默认的请求错误code */
export const DEFAULT_REQUEST_ERROR_CODE = 'DEFAULT';
/** 默认的请求错误文本 */
export const DEFAULT_REQUEST_ERROR_MSG = '请求错误~';
/** 请求超时的错误code */
export const REQUEST_TIMEOUT_CODE = 'TIME_OUT';
/** 请求超时的错误文本 */
export const REQUEST_TIMEOUT_MSG = '请求超时~';
/** 默认的请求错误code */
export const NETWORK_ERROR_CODE = 'NETWORK_ERROR';
/** 默认的请求错误文本 */
export const NETWORK_ERROR_MSG = '网络错误';
/** 请求不成功各种状态的错误 */
export const ERROR_STATUS = {
400: '400: 请求出现语法错误~',
401: '401: 用户未授权~',
403: '403: 服务器拒绝访问~',
404: '404: 请求的资源不存在~',
405: '405: 请求方法未允许~',
408: '408: 网络请求超时~',
500: '500: 服务器内部错误~',
501: '501: 服务器未实现请求功能~',
502: '502: 错误网关~',
503: '503: 服务不可用~',
504: '504: 网关超时~',
505: '505: http版本不支持该请求~',
[DEFAULT_REQUEST_ERROR_CODE]: DEFAULT_REQUEST_ERROR_MSG,
};

51
src/service/http/help.ts Normal file
View File

@ -0,0 +1,51 @@
import type { AxiosResponse, AxiosError } from 'axios';
import {
DEFAULT_REQUEST_ERROR_CODE,
DEFAULT_REQUEST_ERROR_MSG,
NETWORK_ERROR_CODE,
NETWORK_ERROR_MSG,
REQUEST_TIMEOUT_CODE,
REQUEST_TIMEOUT_MSG,
ERROR_STATUS,
} from '@/config';
type ErrorStatus = keyof typeof ERROR_STATUS;
/**
* @description: axios返回的http错误
* @param {AxiosError} err
* @return {*}
*/
export function handleHttpError(err: AxiosError) {
const error = {
type: 'axios',
code: DEFAULT_REQUEST_ERROR_CODE,
msg: DEFAULT_REQUEST_ERROR_MSG,
};
// 网络错误
if (!window.navigator.onLine || err.message === 'Network Error') {
Object.assign(error, { code: NETWORK_ERROR_CODE, msg: NETWORK_ERROR_MSG });
}
// 超时错误
if (err.code === REQUEST_TIMEOUT_CODE && err.message.includes('timeout')) {
Object.assign(error, {
code: REQUEST_TIMEOUT_CODE,
msg: REQUEST_TIMEOUT_MSG,
});
}
// 请求错误
if (err.response) {
const errorCode: ErrorStatus = (err.response?.status as ErrorStatus) || 'DEFAULT';
const msg = ERROR_STATUS[errorCode];
Object.assign(error, { code: errorCode, msg });
}
return error;
}
/**
* @description: axios请求成功
* @param {AxiosResponse} err
* @return {*}
*/
// export function handleResponseError(err: AxiosResponse) {}
// export function handleBusinessError() {}

View File

@ -1,105 +1,69 @@
import axios from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { getToken } from '@/utils';
// import { handleHttpError, handleResponseError, handleBusinessError } from './help';
import { handleHttpError } from './help';
/**
* @description: axios请求类
*/
export default class createAxiosInstance {
// axios 实例
instance: AxiosInstance;
// 后台字段配置
backendConfig: Service.BackendResultConfig;
// 基础配置
axiosConfig: AxiosRequestConfig = {};
// axios 实例
instance: AxiosInstance;
// 后台字段配置
backendConfig: Service.BackendResultConfig;
// 基础配置
axiosConfig: AxiosRequestConfig = {};
constructor(
axiosConfig: AxiosRequestConfig,
backendConfig: Service.BackendResultConfig = {
codeKey: 'code',
dataKey: 'data',
msgKey: 'msg',
successCode: '200',
},
) {
this.backendConfig = backendConfig;
// 设置了axios实例上的一些默认配置,新配置会覆盖默认配置
this.instance = axios.create({ timeout: 60000, ...axiosConfig });
constructor(
axiosConfig: AxiosRequestConfig,
backendConfig: Service.BackendResultConfig = {
codeKey: 'code',
dataKey: 'data',
msgKey: 'msg',
successCode: '200',
}
) {
this.backendConfig = backendConfig;
// 设置了axios实例上的一些默认配置,新配置会覆盖默认配置
this.instance = axios.create({ timeout: 60000, ...axiosConfig });
this.setInterceptor();
}
this.setInterceptor();
}
// 设置类拦截器
setInterceptor() {
this.instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 一般会请求拦截里面加token
config.headers!.Authorization = getToken();
return config;
},
(err: any) => Promise.reject(err),
);
this.instance.interceptors.response.use(
// 因为接口的数据都在res.data下所以直接返回res.data
// 系统如果有自定义code也可以在这里处理
(res: AxiosResponse) => {
// apiData 是 API 返回的数据
const apiData = res.data;
// 这个 Code 是和后端约定的业务 Code
const code = String(res.data[this.backendConfig.codeKey]);
switch (code) {
case this.backendConfig.successCode:
// code === 200 代表没有错误,直接返回约定的数据内容
return apiData;
default:
// 不是正确的 Code,返回错误提示信息
return Promise.reject(new Error(`Error:${this.backendConfig.dataKey}`));
}
},
(err: any) => {
// 这里用来处理http常见错误进行全局提示
let message = '';
switch (err.response.status) {
case 400:
message = '请求错误(400)';
break;
case 401:
message = '未授权,请重新登录(401)';
// 这里可以做清空storage并跳转到登录页的操作
break;
case 403:
message = '拒绝访问(403)';
break;
case 404:
message = '请求出错(404)';
break;
case 408:
message = '请求超时(408)';
break;
case 500:
message = '服务器错误(500)';
break;
case 501:
message = '服务未实现(501)';
break;
case 502:
message = '网络错误(502)';
break;
case 503:
message = '服务不可用(503)';
break;
case 504:
message = '网络超时(504)';
break;
case 505:
message = 'HTTP版本不受支持(505)';
break;
default:
message = `连接出错(${err.response.status})!`;
}
// 这里是AxiosError类型所以一般我们只reject我们需要的响应即可
return Promise.reject(err.response);
},
);
}
// 设置类拦截器的函数
setInterceptor() {
this.instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 一般会请求拦截里面加token
config.headers!.Authorization = getToken();
return config;
},
(err: any) => Promise.reject(err)
);
this.instance.interceptors.response.use(
// 因为接口的数据都在res.data下所以直接返回res.data
// 系统如果有自定义code也可以在这里处理
(res: AxiosResponse) => {
// apiData 是 API 返回的数据
const apiData = res.data;
// 这个 Code 是和后端约定的业务 Code
const code = String(res.data[this.backendConfig.codeKey]);
switch (code) {
case this.backendConfig.successCode:
// code === 200 代表没有错误,直接返回约定的数据内容
return apiData;
default:
// 不是正确的 Code,返回错误提示信息
return Promise.reject(new Error(`Error:${this.backendConfig.dataKey}`));
}
},
(err: AxiosError) => {
// 这里用来处理http常见错误进行全局提示等
const error = handleHttpError(err);
// 这里是AxiosError类型所以一般我们只reject我们需要的响应即可
return Promise.reject(error);
}
);
}
}

View File

@ -7,77 +7,89 @@ import createAxiosInstance from './instance';
* @param {Service} backendConfig -
* @return {*}
*/
export function createRequest(axiosConfig: AxiosRequestConfig, backendConfig?: Service.BackendResultConfig) {
const axiosInstance = new createAxiosInstance(axiosConfig, backendConfig);
const { instance } = axiosInstance;
export function createRequest(
axiosConfig: AxiosRequestConfig,
backendConfig?: Service.BackendResultConfig
) {
const axiosInstance = new createAxiosInstance(axiosConfig, backendConfig);
const { instance } = axiosInstance;
/**
* @description:
* @param {string} url-
* @param {RequestMethod} method -
* @param {any} data -
* @param {AxiosRequestConfig} config -
* @return {*}
*/
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
const request = async (url: string, method: RequestMethod = 'get', data: any, config?: AxiosRequestConfig) => {
return instance(url, { method, data, ...config });
};
/**
* @description:
* @param {string} url-
* @param {RequestMethod} method -
* @param {any} data -
* @param {AxiosRequestConfig} config -
* @return {*}
*/
type RequestMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
const request = async (
url: string,
method: RequestMethod = 'get',
data: any,
config?: AxiosRequestConfig
) => {
return instance(url, { method, data, ...config });
};
/**
* @description: get请求
* @param {string} url -
* @return {*}
*/
const get = async (url: string, config?: AxiosRequestConfig) => {
return instance.get(url, config);
};
/**
* @description: get请求
* @param {string} url -
* @return {*}
*/
const get = async (url: string, config?: AxiosRequestConfig) => {
return instance.get(url, config);
};
/**
* post请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const post = async (url: string, data?: any, config?: AxiosRequestConfig) => {
return instance.post(url, data, config);
};
/**
* @description: post请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const post = async (url: string, data?: any, config?: AxiosRequestConfig) => {
return instance.post(url, data, config);
};
/**
* Delete请求
* @param url -
* @param config - axios配置
*/
const Delete = async (url: string, config?: AxiosRequestConfig) => {
return instance.delete(url, config);
};
/**
* @description: delete请求
* @param url -
* @param config - axios配置
*/
const Delete = async (url: string, config?: AxiosRequestConfig) => {
return instance.delete(url, config);
};
/**
* put请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const put = async (url: string, data?: any, config?: AxiosRequestConfig) => {
return instance.put(url, data, config);
};
/**
* @description: put请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const put = async (url: string, data?: any, config?: AxiosRequestConfig) => {
return instance.put(url, data, config);
};
/**
* patch请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const patch = async (url: string, data?: any, config?: AxiosRequestConfig) => {
return instance.patch(url, data, config);
};
/**
* @description: patch请求
* @param url -
* @param data - body的data
* @param config - axios配置
*/
const patch = async (
url: string,
data?: any,
config?: AxiosRequestConfig
) => {
return instance.patch(url, data, config);
};
return {
request,
get,
post,
Delete,
put,
patch,
};
return {
request,
get,
post,
Delete,
put,
patch,
};
}