后端接口返回的时间 和 axios 从 request 到 response 过程的时间 相差巨大?

后端接口返回的时间 和 axios 从 request 到 response 过程的时间 相差巨大?

背景
在用扫码枪扫货品的时候会调接口 每扫一个货品需要请求三个不同接口 在扫前40个货品的时候时间相差不大, 但是一直扫到150+货品的时候 就会出现 时间相差很大的情况


 

图一是接口返回的时间180ms 图三 从axios request 到 response 前 变成了 800ms
图四 在组件内发起请求到数据返回 时间变成了差不多1800ms 中间没做数据操作 只有增加了请求拦截和响应错误码处理 中间的时间相差这么多 是什么问题导致呢?

// import axios from 'axios'
import axios, { AxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios';
import baseUrl, { differUrl } from './baseUrl';
import router from '@/router';
import store from '@/store';
import { Message } from 'element-ui';
import { vMessage } from '@rbp/components/base-message';
import { filedMapData, moduleIdMapData } from './config';

import { hideScreenLoading, showScreenLoading } from '@/utils/loading';
import { getCookie, getToken, removeCookie } from '@/utils/auth';

let configChace: any = null; // 存放请求参数,在进入错误时候也关掉loading

const CANCELTTYPE = {
    CACHE: 1,
    REPEAT: 2
};

interface Request {
    onlyKey: string;
    url: string;
    source: CancelTokenSource;
}

const pendingRequests: Request[] = [];
const config = {
    // timeout: 1000 * 60 * 10
    // baseURL: baseUrl
};
// eslint-disable-next-line no-unused-vars
const _axios = axios.create(config);

const DELAY = 0;
let timer: any, loadingInstance: any;
const setBaseUrl = (config) => {
    const initUrl = config.url;
    if (initUrl && initUrl.startsWith('/customize')) {
        config.baseURL = differUrl || baseUrl;
        config.baseURL = config.baseURL.replace('/manager', '');
        config.timeout = 1000 * 60 * 10;
    } else if (initUrl && initUrl.startsWith('/report')) {
        config.baseURL = (Window as any).config.reportUrl || baseUrl;
        config.timeout = 1000 * 60 * 10;
    } else if (initUrl && initUrl.startsWith('/new-mf-fac')) {
        config.baseURL = localStorage.getItem('JuNiu_WebAddress') || baseUrl;
        config.timeout = 1000 * 60 * 10;
    } else {
        config.baseURL = baseUrl;
        config.timeout = 1000 * 60 * 3;
    }
};
const setToken = (config) => {
    const token = getToken();
    const refreshToken = getCookie('refreshToken');
    config.headers.Lang = getCookie('language') || 'zh_chs';
    if (token) {
        config.headers['Authorization'] = token; // 让每个请求携带自定义token 请根据实际情况自行修改
    }
    if (refreshToken) {
        config.headers['RefreshToken'] = refreshToken;
    }
};
const setModuleId = (config) => {
    const formatRouter: any = (window as any).__POWERED_BY_QIANKUN__ ? (window as any).ymyCustomizeRouter : router;
    // 模块 ID 参数 全局传入
    // const moduleId = (router as any).history.current.meta.moduleId;
    // let moduleId =
    //     (window as any).Vue2 && (window as any).Vue2.prototype
    //         ? (window as any).Vue2.prototype._router_.history.current.meta.moduleId
    //         : (router as any).history.current.meta.moduleId;
    let moduleId =
        (window as any).Vue2 && (window as any).Vue2.prototype
            ? (window as any).Vue2.prototype._router_.history.current.meta.moduleId
            : formatRouter.history.current.meta.moduleId;
    // 对于非/customize接口,替换moduleId为新moduleId

    if (config?.url.indexOf('/customize') < 0 && config?.url.indexOf('/role/authority') < 0) {
        const obj = moduleIdMapData(config.url, moduleId) || filedMapData(config.url, moduleId);
        if (obj?.moduleId) {
            config.url = obj.url;
            moduleId = obj.moduleId;
            if (config.params) {
                Object.keys(config.params).forEach((key) => {
                    if (['baseModuleId', 'moduleId'].includes(key)) {
                        config.params[key] = obj.moduleId;
                    }
                });
            }
        }
    }
    // if (moduleId && config.data) {
    // if (config.data && config.data.moduleId) {
    //     Object.assign(config.data, { moduleId: config.data.moduleId });
    // }
    if (moduleId && config.data) {
        // NetNeedModuleId 接口不需要 moduleId 为 true 则不需要加
        if (config.data.NetNeedModuleId) {
            delete config.data.NetNeedModuleId;
        } else {
            if (Object.keys(config.data).indexOf('moduleId') > -1) {
                moduleId = config.data.moduleId;
            }
            Object.assign(config.data, { moduleId: moduleId });

            if (typeof config.data.data === 'object') {
                if (config?.url.indexOf('/customize') < 0) {
                    // 对于非/customize接口,将参数中moduleId替换为新moduleId
                    if (Object.keys(config.data.data).indexOf('moduleId') > -1) {
                        config.data.data.moduleId = moduleId;
                    }
                } else {
                    if (Object.keys(config.data.data).indexOf('moduleId') > -1 && config.data.data.moduleId) {
                        moduleId = config.data.data.moduleId;
                    }
                }
                Object.assign(config.data.data, { moduleId: moduleId });
            }
        }

        if (config.data.setModuleIdInHeaders) {
            config.headers['moduleId'] = moduleId;
            delete config.data.setModuleIdInHeaders;
        }
    }
};
const setLoading = (config) => {
    configChace = config;
    // NetNeedModuleId 接口不需要 moduleId 为 true 则不需要加
    if (config.method === 'get' && (!config.params || !config.params.NetNeedLoading)) {
        config.headers['showLoading'] = true;
        showScreenLoading(config.headers);
    } else if (['put', 'post'].includes(config.method) && (!config.data || !config.data.NetNeedLoading)) {
        config.headers['showLoading'] = true;
        showScreenLoading(config.headers);
    }
    config.params && delete config.params.NetNeedLoading;
    config.data && delete config.data.NetNeedLoading;
};
const preventSomeRequest = (config) => {
    /**
     * 为每一次请求生成一个cancleToken
     */
    const source = axios.CancelToken.source();

    config.cancelToken = source.token;
    /**
     * 将之前的重复且未完成的请求全部取消
     */
    const params = JSON.stringify(config.params || config.data);

    const hits = pendingRequests.filter((item) => item.onlyKey === `${config.baseURL}${config.url}${params}`);

    if (hits.length > 0) {
        console.error('有重复请求', hits, config);
        hits.forEach((item) => item.source.cancel(CANCELTTYPE.REPEAT.toString()));
    }

    pendingRequests.push({
        onlyKey: `${config.baseURL}${config.url}${params}`,
        url: `${config.baseURL}${config.url!}`,
        source
    });
};
_axios.interceptors.request.use(
    function (config: AxiosRequestConfig) {
        // 全局请求的 loading,当请求 100 ms 后还没返回,才会出现 loading
        console.time('_axios.interceptors.request 请求设置header等等信息');
        console.time('请求整理到返回中途所需要时间');
        config.headers['request-startTime'] = new Date().getTime();
        setBaseUrl(config);
        setToken(config);
        setModuleId(config);
        setLoading(config);
        // preventSomeRequest(config);
        console.timeEnd('_axios.interceptors.request 请求设置header等等信息');

        return config;
    },
    function (error) {
        // clearTimeout(timer);
        // if (loadingInstance) loadingInstance.close();
        // if (config!.headers.showLoading) {
        if (configChace.headers['showLoading']) {
            hideScreenLoading();
            configChace = null;
        }

        // }
        return Promise.reject(error);
    }
);

// Add a response interceptor
_axios.interceptors.response.use(
    function (response: AxiosResponse) {
        // clearTimeout(timer);
        // if (loadingInstance) loadingInstance.close();
        const headers = response.config.headers;
        headers && headers.showLoading && hideScreenLoading();


        /**
         * code为非20000是抛错 可结合自己业务进行修改
         */
        /**
         * 不论请求是否成功,
         * 将本次完成的请求从请求队列中移除
         */
        // 以同样的加密方式(MD5)获取加密字符串
        const index = pendingRequests.findIndex((item) => item.url === response.config.url);
        //

        if (index > -1) {
            pendingRequests.splice(index, 1);
        }
        if (response.config.responseType === 'blob') {
            return response.data;
        }
        const res = response.data;
        const FIXCODE = [
            0,
            10008,
            10107,
            10112,
            10111,
            10010,
            20001,
            30001,
            30102,
            30103,
            30105,
            30106,
            40100,
            40110,
            40120,
            40121,
            40130,
            40131,
            40140,
            40141,
            40142,
            40160,
            40161,
            40170,
            40180,
            50006,
            50008,
            50009,
            50011,
            50013,
            50014,
            50015,
            50016,
            50017,
            50018,
            50019,
            50020,
            50021,
            50022,
            50024,
            50028, // 联营结算模式审核异常code码
            50029,
            50030,
            50025, // 成本结存异常码(未做库存结存的渠道)
            50031, // 成本结存异常码(存在以下未审核单据)
            50032, // 成本结存异常码(存在本期数量未负的货品)
            50033
        ];
        const NO_TOKEN_CODE = [10006]; // 没有权限或者和token失效
        const PROGRAM_ERROR_CODE = [500, 10001, 10002]; // 显示错误具体信息弹窗 带复制等功能

        console.timeEnd('请求整理到返回中途所需要时间');

        if (PROGRAM_ERROR_CODE.includes(res.code)) {
            // Infrom({ type: 'error', content: res.msg, detail: res.errorStack, confirmButtonText: '关闭' });
            Message({
                type: 'error',
                message: res.msg,
                duration: 3500
            });
            return Promise.reject('error');
        } else if (FIXCODE.includes(res.code)) {
            const start = response.config.headers['request-startTime'];
            const currentTime = new Date().getTime();
            const requestDuration = ((currentTime - start) / 1000).toFixed(2) + 's';
            console.log(`%caxios.ts line:288 ${response.config.url} 接口花费时间`, 'requestDuration', requestDuration);
            // return res;
            return Promise.resolve(res);
        } else if (NO_TOKEN_CODE.includes(res.code)) {
            //接口登陆失效跳转登录页
            vMessage({
                type: 'error',
                message: res.msg || res.errorStack,
                showClose: true,
                duration: 3500
            });
            removeCookie('tempToken');
            removeCookie('tempRefreshToken');
            store.dispatch('user/resetToken').then(() => {
                setTimeout(() => {
                    window.location.reload();
                }, 500);
            });
            return Promise.reject('loginError');
        } else {
            Message({
                type: 'error',
                message: res.msg || res.errorStack,
                duration: 3500
            });
            return Promise.reject('error');
        }
    },
    function (error) {
        // clearTimeout(timer);
        // if (loadingInstance) loadingInstance.close();
        // if (response.config.headers.showLoading) {

        // }
        // setTimeout(() => {
        //     hideScreenLoading();
        // }, 200);
        // 这里是重复请求不弹出
        if (error.message !== CANCELTTYPE.REPEAT.toString()) {
            if (configChace.headers['showLoading']) {
                hideScreenLoading();
                configChace = null;
            }

            // Infrom({ type: 'error', content: error.msg || '请求超时或服务器异常,请检查网络或联系管理员' });
            Message({
                type: 'error',
                message: error.msg || '请求超时或服务器异常,请检查网络或联系管理员'
            });
        }

        return Promise.reject(error);
    }
);

export default _axios;
阅读 1.4k
2 个回答

主要看图一的数据,延迟应该是服务端导致的吧,再延迟出现的时候,api的耗时是多少,请截图一的数据,分析一下

这段时间涵盖的处理过程太多,尤其是网络过程非常不稳定。要先确定是哪部分造成报时间的大辐增加,如果是网络造成的,那前端不太可能做优化。

如果是想做纯粹的前端监测,从前端可以监测的点开始计时到当前处理不能监测时结束。比如你猜测是拦截引起的效率问题,那你可以只监测这部分处理所花的时间来确认是否是这个问题。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题