import { extend } from 'umi-request'; import type { RequestOptionsInit } from 'umi-request'; import { omit, get } from 'lodash-es'; import { message } from 'antd'; import { User } from '@zhst/types/user'; import base64 from 'base-64'; export class ResponseError extends Error { name; data; response; request; type; constructor( response: Response, text: string, data: D, request: { url: string; options: RequestOptionsInit; }, type = 'ResponseError' ) { super(text || response.statusText); this.name = 'ResponseError'; this.data = data; this.response = response; this.request = request; this.type = type; } } export const req = extend({ getResponse: true, // timeout: 1000, parseResponse: false, }); //错误处理中间件 req.use(async (ctx, next) => { const { req } = ctx; const { toast = true } = req?.options || {}; try { await next(); const { res } = ctx; const d = await res.text(); if (res.status === 401) { localStorage.removeItem(User.TOKEN_KEY); localStorage.removeItem(User.USER_KEY); message.warning('登录过期,请重新登录!'); return; } const isEmptyRes = d === ''; //有些后端接口成功会返回空 做下兼容 if (!res) return const body = !isEmptyRes ? JSON.parse(d) : d; if (res.status >= 200 && res.status < 300) { ctx.res = body; } else { // 先判断Grpc-Metadata-Errorx-Message let errMsg = res.headers.get('Grpc-Metadata-Errorx-Message'); if (errMsg) { errMsg = base64.decode(errMsg) // 后判断 body中的message } else if (!errMsg && get(body, 'message')) { errMsg = `${get(body, 'message')}`; } else { // 最后看状态码 errMsg = '您的网络发生异常,无法连接服务器'; } toast && message.error(errMsg); throw new ResponseError(res, errMsg, d, req, 'CustomError'); } } catch (error) { if (get(error, 'type') !== 'CustomError') { toast && message.error('您的网络发生异常,无法连接服务器'); } throw error; } }); export interface OPTION extends RequestOptionsInit { toast?: boolean; } interface CGI { method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; url: string; baseUrl?: string; data?: { [key: string]: any }; useBaseUrl?: boolean; originUrl?: boolean; refererSuffix?: string; } export const doRequest = (cgi: CGI, option?: OPTION): Promise => { const { method, url, baseUrl, data = {}, useBaseUrl = true, originUrl = false, refererSuffix = '', } = cgi; const token = localStorage.getItem(User.TOKEN_KEY); let newUrl = ''; if (useBaseUrl) { newUrl = `${baseUrl}${url}`; } else { // 本地Mock -- http://127.0.0.1:4523/m1/2822485-0-default // 7环境gateway -- http://10.0.0.7:32223 newUrl = `http://10.0.0.7:32223${url}`; // 7环境进行调试 } if (originUrl) { newUrl = url; } // 对于 /:id 类的 url 进行参数填充 const regex = /\/:(\w+)/g; // 替换 url 参数 const params = []; let matches; while ((matches = regex.exec(newUrl)) != null) { if (matches[1]) { params.push(matches[1]); } } params.forEach(function (name) { let d = data?.[name]; if (d == null) { d = ''; } newUrl = newUrl.replace(`:${name}`, d); }); //通过method 判断解析成data / params const newData = omit(data, params); const paramObj = method.toLowerCase() === 'get' ? { params: newData } : { data: newData }; return req(newUrl, { method: method, ...paramObj, ...option, headers: { authorization: token!, ...(refererSuffix ? { zhst_referer: `${baseUrl}${refererSuffix}` } : {}), }, }) as Promise; }; export default doRequest;