// import { logRequestDuration } from '@dodoex/mixpanel'; import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import { getIsDevEnvironment, getServiceDomain, getServiceDomainDev, } from './domains'; const isDev = getIsDevEnvironment(); export type RequestResponse = AxiosResponse; // Set config defaults when creating the instance // let requestStartTime: string; const instance = axios.create({ method: 'post', headers: { 'Content-Type': 'application/json', }, withCredentials: false, timeout: 30000, }); instance.interceptors.request.use((config) => { // requestStartTime = String(performance.now()); return config; }); instance.interceptors.response.use((response) => { // const start = requestStartTime ?? 0; // header中的track id字段名后续需要统一, 待后端确认! // const trackId = response.headers['x-dodo-route-trace-id'] ?? ''; // const time = performance.now() - +start; // const duration = String(parseInt(String(time), 10)); // logRequestDuration( // response.config.url || '', // Number(duration), // trackId as string, // ); return response; }); /** * apollo client endpoint */ export const ApolloGQLClientDevEndpoint = `https://api.${getServiceDomainDev()}/frontend-graphql`; export const ApolloGQLClientEndpoint = `https://api.${getServiceDomain()}/frontend-graphql`; // export const ApolloMessageGQLClientDevEndpoint = `wss://api.${getServiceDomainDev()}/frontend-message/graphql`; export const ApolloMessageGQLClientDevEndpoint = `wss://message.${getServiceDomainDev()}/graphql`; export const ApolloMessageGQLClientEndpoint = `wss://message.${getServiceDomain()}/graphql`; export const kStaticServerEndPoint = `https://cdn-static.${getServiceDomain()}`; /** * @author https://www.showdoc.com.cn/p/2b142f133b5070f99977a503112b0d85 */ export const DODO_BUSINESS_BACKEND_API_URL = isDev ? `https://api.${getServiceDomainDev()}/frontend-business-data` : `https://api.${getServiceDomain()}/frontend-business-data`; /** * price-api */ export const DODO_PRICE_BACKEND_API_URL = `https://api.${isDev ? getServiceDomainDev() : getServiceDomain()}/frontend-v2-price-api`; /** * route-api */ /** 新的网关 */ /** * 不收费路由正式链接 * @deprecated */ export const ROUTE_API_URL = `https://api.${getServiceDomain()}/route-service/frontend/getdodoroute`; /** * 不收费路由测试链接 * @deprecated */ export const ROUTE_API_URL_DEV = `https://api.${getServiceDomainDev()}/route/getdodoroute`; /** 收费路由正式链接 */ export const ROUTE_API_URL_V2 = `https://api.${getServiceDomain()}/route-service/frontend-v2/getdodoroute`; /** 收费路由测试链接 */ export const ROUTE_API_URL_DEV_V2 = `https://api.${getServiceDomainDev()}/route/fee/getdodoroute`; /** * 询价接口改造 * route-api 不再需要区分不同的接口地址,服务器端会自动分流 * @see https://www.notion.so/dodotopia/802328f5601f49c0821076473bc2982d?pvs=4 */ // export const ROUTE_API_URL_V3 = `https://api.${getServiceDomain()}/route-service-cloudrun/frontend/getdodoroute`; export const ROUTE_API_URL_V3 = `https://api.${getServiceDomain()}/route-service/frontend-v2/getdodoroute`; export const ROUTE_API_URL_DEV_V3 = `https://api.${getServiceDomainDev()}/route/fee/getdodoroute`; /** algolia 搜索服务 */ export const ALGOLIA_SEARCH_URL = `https://api.${getServiceDomain()}/algolia`; export const ALGOLIA_SEARCH_URL_DEV = `https://api.${getServiceDomainDev()}/algolia`; /** * mixpanel */ export const MixpanelProxyURLDev = `https://api.${getServiceDomainDev()}/frontend-wua/m`; export const MixpanelProxyURL = `https://api.${getServiceDomain()}/frontend-wua/m`; /** * gateway dashboard */ export const GatewayDashboardURLDev = `https://gateway-manage.${getServiceDomainDev()}`; export const GatewayDashboardURL = `https://gateway-manage.${getServiceDomain()}`; /** * gateway dashboard-config-center */ export const CONFIG_CENTER_URL = `https://api.${ isDev ? getServiceDomainDev() : getServiceDomain() }/config-center`; /** * upload image */ export const UPLOAD_IMAGE_URL = `https://api.${ isDev ? getServiceDomainDev() : getServiceDomain() }/gateway/upload`; /** * api */ export const API_URL = `https://api.${ isDev ? getServiceDomainDev() : getServiceDomain() }`; export const TOKEN_LOGO_URL = `https://token-img.${ isDev ? getServiceDomainDev() : getServiceDomain() }`; /** * 又一个后端接口? * 目前用于限价单提交订单和查看订单 * @deprecated */ export const ORDER_API_URL = isDev ? `https://order.${getServiceDomainDev()}` : `https://order.${getServiceDomain()}`; /** * ORDER_API_URL 对应的后端返回的 message 类型 * * message: { * title: "", // i18n key 表示弹窗标题 * desc: "" i18n key 弹窗引导语 * } */ export const ORDER_API_MESSAGE_MAP: Record< string, { title: string; desc?: string; } > = { // https://www.notion.so/dodotopia/3b24eea548164d5ca86d91703a7000c0#c37eb4bfd7a649eeb55785138219453f ORDER_STATUS_NOT_FRESH: { title: 'limit.order.cancel.failed', desc: 'limit.order.cancel.failed.desc', }, 'Invalid signature time.': { title: 'Invalid signature time.', }, NONE_USEFUL_SELLER_OFFER: { title: 'rfq.api.error1', }, OFFER_DEAL_ERROR: { title: 'rfq.api.error2', }, 'Authentication Failure': { title: 'rfq.api.error.authorization', }, }; interface Config { timeout?: number; /** 中断回调 */ setAbort?: (abort: () => void) => void; } interface Props { url: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any params?: any; config?: Config & Pick; } interface ProcessProps extends Props { method?: 'get' | 'post'; } const processRequest = async ({ url, params, config, method = 'get', }: ProcessProps) => { const { timeout, setAbort, headers } = config || {}; // https://axios-http.com/docs/cancellation // 该 api 0.22.0 之后已经废弃,但因为目前项目中用的是 0.21.1,所以先按这种用法。后续升级后需更换 // axios 已升级至 ^0.27.2, 可以替换 // const { CancelToken } = axios; // const source = CancelToken.source(); const controller = new AbortController(); const options: AxiosRequestConfig = { signal: controller.signal, headers, }; if (timeout) { setTimeout(() => { controller.abort(); }, timeout); } if (setAbort) { setAbort(() => { controller.abort(); }); } const result = method.toLowerCase() === 'get' ? await instance.get(url, { ...options, params }) : await instance.post(url, params, options); return result as RequestResponse; }; export const get = async (options: Props) => { return processRequest({ ...options, method: 'get', }); }; export const post = async (options: Props) => { return processRequest({ ...options, method: 'post', }); }; // Alter defaults after instance has been created // instance.defaults.headers.common['Authorization'] = AUTH_TOKEN; export default instance;