yangyin
2024-07-15 0e982d78030d36d6048532f5d4a848ad9a22a13f
src/utils/request.ts
@@ -1,75 +1,37 @@
import type { AxiosInstance, AxiosRequestConfig } from 'axios';
import axios from 'axios';
import { ElMessage } from 'element-plus';
import emitter from './mitt';
import { debounce } from './util';
import { AUTH_URL, MAIN_URL, SECONDARY_URL } from '/@/constants';
import { Local, Session } from '/@/utils/storage';
// import JSONbig from 'json-bigint';
//#region ====================== 后端 res.Code ======================
// // 摘要:
// //     成功
// Success = 0,
// //
// // 摘要:
// //     确认(权限验证使用)
// Confirm = -1,
// //
// // 摘要:
// //     提示(验证失败后使用)
// Prompt = -2,
// //
// // 摘要:
// //     警告(业务异常使用)
// Alert = -3,
// //
// // 摘要:
// //     错误(未捕获系统异常使用)
// Error = -4,
// //
// // 摘要:
// //     超时(暂不使用)
// TimeOut = -5
//#region ====================== 后端 res.err_code ======================
export const enum ErrorCode {
   /** @description 权限验证失败 */
   Auth = 'AUTH',
}
//#endregion
const initRequestInterceptor = (request: AxiosInstance,isAuth=false) => {
const handleNoAuth = debounce(() => {
   emitter.emit('logout');
   emitter.emit('openLoginDlg');
});
const loginUrl = '/login';
const initRequestInterceptor = (request: AxiosInstance) => {
   // 添加请求拦截器
   request.interceptors.request.use(
      (config) => {
         // // 在发送请求之前做些什么 token
         // if (Local.get(accessTokenKey)) {
         //    (<any>config.headers).common['Authorization'] = `${Session.Local('token')}`;
         // }
         // 获取本地的 token
         const accessToken = Local.get(accessTokenKey);
         if (accessToken) {
            // 将 token 添加到请求报文头中‘
            if(isAuth){
               config.headers!['Authorization'] = `Bearer ${accessToken}`;
            }else{
               config.headers['Referrer-Policy'] = undefined;
            }
            // 判断 accessToken 是否过期
            const jwt: any = decryptJWT(accessToken);
            const exp = getJWTDate(jwt.exp as number);
            const isExpired = new Date() >= exp;
            // token 已经过期
            if (isExpired) {
               // 获取刷新 token
               const refreshAccessToken = Local.get(refreshAccessTokenKey);
               // 携带刷新 token
               if (refreshAccessToken) {
                  config.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`;
               }
            }
            // get请求映射params参数
            if (config.method?.toLowerCase() === 'get' && config.data) {
               let url = config.url + '?' + tansParams(config.data);
               url = url.slice(0, -1);
               config.data = {};
               config.url = url;
         const accessSession = Local.get(accessSessionKey);
         if (accessSession) {
            // 将 token 添加到请求报文头中
            config.headers['hswatersession'] = accessSession;
         } else {
            if (config.url !== loginUrl) {
               handleNoAuth(config.url);
               throw '权限验证失败';
            }
         }
         return config;
@@ -85,12 +47,12 @@
      (res) => {
         // 获取状态码和返回数据
         const status = res.status;
         const serve = res.data;
         // code 为 -1 就是权限验证失败
         if (serve?.code === -1) {
            clearAccessTokens();
            window.location.reload();
         const serveData = res.data;
         if (!serveData) {
            ElMessage.error('请求失败');
            throw new Error('请求失败');
         }
         // 处理 401
         if (status === 401) {
            clearAccessTokens();
@@ -100,45 +62,23 @@
         if (status >= 400) {
            throw new Error(res.statusText || 'Request Error.');
         }
         // 处理规范化结果错误
         if (serve && serve.hasOwnProperty('errors') && serve.errors) {
            throw new Error(JSON.stringify(serve.errors || 'Request Error.'));
         }
         // 读取响应报文头 token 信息
         // 只能叫 access-token
         const accessToken = res.headers['access-token'];
         // 只能叫 x-access-token'
         const refreshAccessToken = res.headers['x-access-token'];
         // 判断是否是无效 token
         if (accessToken === 'invalid_token') {
            // ElMessage.error('登录失效');
            clearAccessTokens();
            window.location.reload();
         }
         // 判断是否存在刷新 token,如果存在则存储在本地
         else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
            Local.set(accessTokenKey, accessToken);
            Local.set(refreshAccessTokenKey, refreshAccessToken);
         }
         if (!serve.json_ok && !isAuth) {
            // ElMessage.warning(serve.json_msg)
            throw new Error('响应错误');
         }
         // 响应拦截及自定义处理
         if (serve.data === 401) {
            clearAccessTokens();
         } else if (serve.code === undefined) {
            return Promise.resolve(res.data);
            // return res.data;
         } else if (serve.code !== 200) {
            const message = JSON.stringify(serve.message);
         if (!serveData.json_ok) {
            switch (serveData?.err_code) {
               case ErrorCode.Auth:
                  if (res.config.url !== loginUrl) {
                     handleNoAuth();
                     throw '权限验证失败';
                  }
            }
            const msg = serveData.json_msg ?? '';
            ElMessage.error(message);
            throw new Error(message);
            const error = serveData?.err_code ? `${msg ? `【${serveData.err_code}】` : serveData.err_code}` : '';
            const tip = error + msg || '请求失败';
            ElMessage.error(tip);
            const url = res.request.responseURL;
            throw new Error(url + '\n' + tip);
         }
         return res.data;
      },
@@ -165,21 +105,18 @@
   );
};
// 配置新建一个 axios 实例
const service = axios.create({
   baseURL: MAIN_URL,
   timeout: 50000,
   headers: { 'Content-Type': 'application/json;charset=utf-8 ' },
const createAxiosInstance = () => {
   return axios.create({
      baseURL: MAIN_URL,
      timeout: 50000,
      headers: { 'Content-Type': 'application/json;charset=utf-8 ' },
   });
};
const service = createAxiosInstance();
});
export const mainRequest = service;
const authService = axios.create({
   // baseURL: MAIN_URL,
   timeout: 50000,
   headers: { 'Content-Type': 'application/json;charset=utf-8 ' },
});
initRequestInterceptor(service);
initRequestInterceptor(authService,true)
export function secondaryRequest(config: AxiosRequestConfig<any>) {
   return service({
@@ -192,7 +129,7 @@
 * 用于访问登录接口
 */
export function authRequest(config: AxiosRequestConfig<any>) {
   return authService({
   return service({
      ...config,
      baseURL: AUTH_URL,
   });
@@ -207,21 +144,22 @@
   .join('-');
const domainPrefix = subDomainName ? `${subDomainName}-` : '';
// token 键定义
export const accessTokenKey = domainPrefix + 'access-token';
export const refreshAccessTokenKey = `x-${accessTokenKey}`;
export const accessSessionKey = domainPrefix + 'access-session';
export const userNameKey = domainPrefix + 'userName';
export const refreshAccessTokenKey = `x-${accessSessionKey}`;
// userInfo键定义
export const userInfoKey = domainPrefix + 'userInfo';
// 获取 token
export const getToken = () => {
   return Local.get(accessTokenKey);
export const getSession = () => {
   return Local.get(accessSessionKey);
};
// 清除 token
export const clearAccessTokens = async () => {
   Local.remove(accessTokenKey);
   Local.remove(refreshAccessTokenKey);
   Local.remove(accessSessionKey);
   // 清除用户信息(每次刷新都需要利用用户信息去请求对应权限菜单)
   Local.remove(userInfoKey);
   // 清除其他