濰坊做網(wǎng)站網(wǎng)站安全
通常在開發(fā)時(shí),后端向前端返回的數(shù)據(jù)可以如下:
- 1 使用restful api充分利用http狀態(tài)碼,然后在data中追加code字段,請(qǐng)求成功返回200,請(qǐng)求失敗返回404,401,500等狀態(tài)碼,并且在code字段中給出詳細(xì)的字符串信息
- 2 再包一層,所有請(qǐng)求不論失敗還是成功狀態(tài)返回均為200,然后在code中,返回實(shí)際的成功或失敗的原因(可以是number,也可以是string)
以下以第二種為例:
type Content = Array<unknown> | Record<string, unknown> | null;interface CustomResponse<T extends Content = Content> {code: number;//具體的code,這里依然使用的400,401等200表示成功data: T;msg: string;
}export enum Method {/** Get請(qǐng)求 */Get = 'GET',/** Post請(qǐng)求 */Post = 'POST',/** Put請(qǐng)求 */Put = 'PUT',/** Delete請(qǐng)求 */Delete = 'DELETE',
}
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import router from '@/router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { localStorage } from '@/storage';
import { Method } from '@/enum';
import useStore from '@/store';
import qs from 'qs';// 白名單列表,用于直接顯示前端定義的錯(cuò)誤
const whiteList: string[] = [];const requests: any[] = [];
const cancelRequest = (config: any, cancelAll = false) => {for (const req in requests) {if (!cancelAll) {if (requests[req].url === `${config.method}-${config.url}`) {requests[req].controller.abort();requests.splice(Number(req), 1);}} else {requests[req].controller.abort();requests.splice(Number(req), 1);}}
};// 創(chuàng)建 axios 實(shí)例
const service = axios.create({baseURL: import.meta.env.DEV ? 'api-dev' : 'api-prod',timeout: 60000,
});// 請(qǐng)求攔截器
service.interceptors.request.use((config: AxiosRequestConfig) => {const { user } = useStore();// 請(qǐng)求自動(dòng)添加tokenif (user.token) {config.headers!.Authorization = `${localStorage.get('token')}`;}// 請(qǐng)求隊(duì)列,用于取消請(qǐng)求const controller = new AbortController();config.signal = controller.signal;requests.push({url: `${config.method}-${config.url}`,controller: controller,});return config;},error => {return Promise.reject(error);}
);// 響應(yīng)攔截器
service.interceptors.response.use((response: AxiosResponse) => {const { status } = response;if (status === 200) {switch (response.data.code) {case 200:return response.data;case 404:// 自定義的錯(cuò)誤碼,可以與http狀態(tài)碼一致,前后端約定即可// 同時(shí)根據(jù)錯(cuò)誤碼進(jìn)行跳轉(zhuǎn),清空緩存等動(dòng)作break;......default:break;}}return response.data;},error => {return Promise.reject(new Error(error.message || 'Error'));}
);function customRequest(method: Method
): <T extends Content>(url: string,data?: Record<string, any>,options?: AxiosRequestConfig
) => Promise<T> {return async function <T extends Content>(url: string,data?: Record<string, any>,options?: AxiosRequestConfig) {let restParams = {};if (method === Method.Get) {restParams = {params: { ...data?.params },paramsSerializer: function (params: any) {//arg: [1, 2]會(huì)被轉(zhuǎn)換為不同形式: indices轉(zhuǎn)換為'arg[0]=1&arg[1]=2' brackets轉(zhuǎn)換為'arg[]=1&arg[]=2' repeat轉(zhuǎn)換為'arg=1&arg=2'return qs.stringify(params, { arrayFormat: 'repeat' }); },};} else {restParams = {data,...options,};}const res = await service.request<T, CustomResponse<T>>({ url, method: method, ...restParams });// 為了不在每個(gè)請(qǐng)求后添加如下代碼,所以在此統(tǒng)一處理if (res.code === 200 && res.data) {return res.data;}throw res.msg;};
}// axios 實(shí)例
export default service;// 自定義axios 實(shí)例
export const requestService = {get: customRequest(Method.Get),post: customRequest(Method.Post),put: customRequest(Method.Put),delete: customRequest(Method.Delete),
};
export { cancelRequest, requests };