Маршрут переключения Axios для отмены указанного запроса и отмены схемы сосуществования дублирующих запросов

внешний интерфейс axios

предисловие

Существует бесчисленное множество статей и источников о запросах на отмену аксиом. Большинство представлено индивидуальноПри переключении маршрутов отменять незавершенные запросы на предыдущей страницеилиОтменить дублирующий запросВ статьях, а большинство из них знакомят с основным содержанием, отсутствует описание полного набора программ.

В этой статье представлен такой полный набор решений, который может удовлетворитьПереключить маршрут, чтобы отменить указанный запроса такжеОтменить дублирующий запрос, и поставляется с некоторыми другими мелкими галантерейными изделиями

запрос на перехват

По поводу запроса на отмену axios, в официальном документе тоже кратко описан метод использования, я не буду здесь повторять основной метод, а напишу план напрямую.

Идеи:

Используйте переменную для хранения текущего ожидающего запроса, обозначенного флагом. Перехватите запрос на отправку и оцените, был ли запрос API в ожидании ранее, то есть существует ли он в вышеуказанных переменных, если он существует, отмените обработку, если он не существует, отправьте его в обычном режиме и удалите запрос API. после завершения запроса. В приведенных выше переменных , что представляет собой завершенный процесс обработки отмены повторяющихся запросов.

Для переключенного маршрута (страницы), если вы хотите отменить ожидающий запрос на предыдущей странице, вам необходимо отслеживать переключатель маршрута.Каждый переключатель будет оценивать идентификатор запроса, хранящийся в указанной выше переменной, и отменять запросы, которые должны быть отменены. , Вот и все. Обработка отмены для всех запросов в состоянии ожидания не производится, так как некоторые запросы в системе могут быть отменены из-за переключения маршрутов, например, некоторые глобальные запросы. Конечно, это также может быть расширено для ваших реальных потребностей проекта, указав, какие из них необходимо отменить.

По поводу настройки эффекта запроса, я привык к отдельному файлу http.js, а комментарии в коде написаны четко пошагово, и все это естественно поймут после прочтения.

// http.js

import axios from 'axios';

// 用于存储目前状态为pending的请求标识信息
let pendingRequest = [];

/**
 * 请求的拦截处理
 * @param config - 请求的配置项
 */
const handleRequestIntercept = config => {
    // 区别请求的唯一标识,这里用方法名+请求路径
    // 如果一个项目里有多个不同baseURL的请求
    // 可以改成`${config.method} ${config.baseURL}${config.url}`
    const requestMark = `${config.method} ${config.url}`;
    // 找当前请求的标识是否存在pendingRequest中,即是否重复请求了
    const markIndex = pendingRequest.findIndex(item => {
        return item.name === requestMark;
    });
    // 存在,即重复了
    if (markIndex > -1) {
        // 取消上个重复的请求
        pendingRequest[markIndex].cancel();
        // 删掉在pendingRequest中的请求标识
        pendingRequest.splice(markIndex, 1);
    }
    // (重新)新建针对这次请求的axios的cancelToken标识
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    config.cancelToken = source.token;
    // 设置自定义配置requestMark项,主要用于响应拦截中
    config.requestMark = requestMark;
    // 记录本次请求的标识
    pendingRequest.push({
        name: requestMark,
        cancel: source.cancel,
        routeChangeCancel: config.routeChangeCancel // 可能会有优先级高于默认设置的routeChangeCancel项值
    });
    
    return config;
};

/**
 * 响应的拦截处理
 * @param config - 请求的配置项
 */
const handleResponseIntercept = config => {
    // 根据请求拦截里设置的requestMark配置来寻找对应pendingRequest里对应的请求标识
    const markIndex = pendingRequest.findIndex(item => {
        return item.name === config.requestMark;
    });
    // 找到了就删除该标识
    markIndex > -1 && pendingRequest.splice(markIndex, 1);
}

/**
 * 创建axios实例
 * @param {String} url - 访问后台的主url
 */
const createAxiosInstance = (baseUrl) => {
    let instance = axios.create({
        baseURL: baseUrl
    });
    // 默认把请求视为切换路由就会把pending状态的请求取消,false为不取消
    instance.defaults.routeChangeCancel = true;
    
    // 请求拦截
    instance.interceptors.request.use(handleRequestIntercept, error => Promise.reject(error));
    
    // 响应拦截
    instance.interceptors.response.use(res => {
        handleResponseIntercept(res.config);
        // 其实更多情况下你执行获取res.data
        // 可以return res.data;
        return res;
    }, error => {
        let errorFormat = {};
        const response = error.response;
        // 请求已发出,但服务器响应的状态码不在 2xx 范围内
        if (response) {
            handleResponseIntercept(response.config);
            // 设置返回的错误对象格式(按照自己项目实际需求)
            errorFormat = {
                status: response.status,
                data: response.data
            };
        }
        // 如果是主动取消了请求,做个标识
        if (axios.isCancel(error)) {
            errorFormat.selfCancel = true;
        }
        // 其实还有一个情况
        // 在设置引发错误的请求时,error.message才是错误信息
        // 但我觉得这个一般是脚本错误,我们项目提示也不应该提示脚本错误给用户看,一般都是我们自定义一些默认错误提示,如“创建成功!”
        // 所以这里不针对此情况做处理。
        
        return Promise.reject(errorFormat);
    });
    
    // 还有一些其他你想要的axios实例设置
    // ...
    
    return instance;
}

// 其他配置
// ...

export {
    pendingRequest
}

Приведенный выше код может отменить повторный запрос, тогда для отмены отложенного указанного запроса после переключения маршрута нужно следить за изменением маршрута.

В файле настроек маршрутизации вот пример vue-router

// router.js

import { pendingRequest } from 'http.js';

// ...这是其他配置

router.beforeEach((to, from, next) => {
    // 把上个页面还没结束的请求取消掉
    pendingRequest.forEach(item => {
        item.routeChangeCancel && item.cancel();
    });
    // ... 其他处理
});

В реальном приложении проекта

Обработка ошибок

Выше мы решили, как делать перехват и как обрабатывать переключение маршрутов, с чем в основном разобрались.

Также есть небольшие моменты, помните, что мы судили, был ли активно отменен перехват ответа, а затем устанавливалиselfCancelлоготип.

Какая от этого польза? Он используется для обработки, когда мы собираем информацию об ошибках при отправке запросов в проекте. Такие как

// 我创建了axios实例并绑在Vue的http上
Vue.http.get('/api/test').then(res => {
    // 成功请求的处理
}).catch(e => {
    // 这里就要判断是否是主动取消请求的
    e.selfCancel || this.$message.error('请求失败!');
})

здесьthis.$message.errorОн в основном используется для запроса информации об ошибке для просмотра пользователями, и, поскольку мы активно отменили запрос, он будет отправлен вcatchпроцесс, но на самом деле это не ошибка и не должно сообщать пользователю, что что-то пошло не так.

так этоselfCancelЛоготип используется для того, чтобы сообщить разработчику, что это ошибка, вызванная нашей инициативой по отмене запроса, и ее не следует предлагать пользователю.

Различать, запрашивается ли страница

Мы прошли запрос вышеconfig.routeChangeCancelОпределить, следует ли отменять ожидающий запрос при переключении маршрутов.

Мы едины, чтобы установить значение по умолчанию при создании экземпляра axios.routeChangeCancelЕсли это правда, то при каких обстоятельствах это правда? Когда мы переключаем маршруты, мы часто хотим отменить запросы, которые не были выполнены на предыдущей странице, чтобы избежать этого, если есть изменения или методы или объекты DOM, связанные с предыдущей страницей, когда обработка функции обратного вызова завершена из-за переключение запроса маршрутизации, отчетов не будет, ошибки скрипта и т.д. Конечно, это также процесс оптимизации производительности для улучшения взаимодействия с пользователем, поэтому это необходимо.

Некоторые люди могут подумать, что пока маршрут переключается, хорошо ли отменять все незавершенные запросы? Однако в вашей системе могут быть некоторые публичные запросы, на которые не влияет и не должно влиять переключение страниц, такие запросы не должны отменяться при переключении маршрутов! Типичный пример — какую-то информацию в шапке системы нужно получить, отправив запрос, а переключение шапки шапки страницы не изменится, верно?

тогда мы прошлиinstance.defaults.routeChangeCancel = trueПосле его настройки, как настроить, чтобы он знал, какие запросы можно отменить без переключения маршрутов?

Vue.http.get('/api/test', {
    routeChangeCancel: false
})

Когда экземпляр отправляет запрос, этот параметр можно переопределить.

На самом деле, если вы не хотите различать форму этого параметра, вы можете фактически создать два типа экземпляров axios, один из которых указывает, что переключение маршрутов будет отменено, а другой не требует отмены. Но я думаю, что такой запрос, который не нужно отменять, редко встречается в проекте и системе, на самом деле гибкость такой конфигурации лучше, и с ней не будет особых проблем.

Суммировать

Здесь представлен сценарий отмены запроса.

Пожалуйста, не воспроизводите без разрешения

Возникло вК передний конец