В процессе разработки веб-проекта мы часто сталкиваемся со сценариями повторных запросов, если система не обрабатывает повторные запросы, это может вызвать различные проблемы в системе. например, повторныйpost
Запрос может привести к созданию сервером двух записей. Так как же возникают повторные запросы? Здесь мы приводим 2 распространенных сценария:
- Предположим, на странице есть кнопка, и когда пользователь нажимает кнопку, инициируется AJAX-запрос. Если кнопка не контролируется, когда пользователь быстро нажимает кнопку, выполняется повторный запрос.
- Предположим, что на странице запроса результатов экзамена пользователь может«Пройдено», «Не пройдено» и «Все»3 условия запроса для запроса результатов теста. Если ответ на запрос медленный, когда пользователь быстро переключается между различными условиями запроса, будут генерироваться повторные запросы.
Теперь, когда вы знаете, как делаются повторяющиеся запросы, вы также знаете, что это может вызвать некоторые проблемы. Далее Брат А Бао будет использоватьAxiosНапример, возьмем всех за решение проблемы повторных запросов.
Следуйте «Дорога полного стека», чтобы прочитать 4 бесплатные электронные книги (всего более 30 000 загрузок) и 11 руководств по Vue 3 для продвинутых пользователей.
1. Как отменить запрос
Axios— это HTTP-клиент на основе Promise, который поддерживает как браузер, так и среду Node.js. Это отличный HTTP-клиент, широко используемый в большом количестве веб-проектов. Для среды браузера нижний уровень Axios должен использоватьXMLHttpRequestобъект для инициирования HTTP-запросов. Если мы хотим отменить запрос, мы можем позвонитьXMLHttpRequestна объектеabort
метод отмены запроса:
let xhr = new XMLHttpRequest();
xhr.open("GET", "https://developer.mozilla.org/", true);
xhr.send();
setTimeout(() => xhr.abort(), 300);
Для Axios мы можем использовать внутренний Axios для предоставленияCancelToken
чтобы отменить запрос:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
name: 'semlinker'
}, {
cancelToken: source.token
})
source.cancel('Operation canceled by the user.'); // 取消请求,参数是可选的
Кроме того, вы также можете позвонитьCancelToken
конструктор для созданияCancelToken
, следующим образом:
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
cancel(); // 取消请求
Теперь мы знаем, как использовать в AxiosCancelToken
чтобы отменить запрос, затемCancelToken
Как это работает внутри? Здесь мы запомнем этот вопрос сначала, и брат Бао раскроет его вам позже.CancelToken
Секрет позади. Далее давайте проанализируем, как оценивать повторяющиеся запросы.
2. Как оценивать повторяющиеся запросы
Когда метод запроса, URL-адрес запроса и параметры запроса совпадают, мы можем считать запрос одинаковым. Следовательно, каждый раз, когда инициируется запрос, мы можем генерировать уникальный ключ в соответствии с методом запроса, запрашивать URL-адрес и параметры запроса текущего запроса, а также создавать выделенный CancelToken для каждого запроса, а затем использовать ключ и функцию отмены как Пара значений ключа хранится в объекте Map.Преимущество использования Map в том, что он может быстро определить, есть ли повторяющиеся запросы:
import qs from 'qs'
const pendingRequest = new Map();
// GET -> params;POST -> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&');
const cancelToken = new CancelToken(function executor(cancel) {
if(!pendingRequest.has(requestKey)){
pendingRequest.set(requestKey, cancel);
}
})
Когда есть повторный запрос, мы можем использовать функцию отмены, чтобы отменить ранее выданный запрос.После отмены запроса нам также нужно удалить отмененный запрос изpendingRequest
удалено в. Теперь, когда мы знаем, как отменить запрос и как оценить повторяющийся запрос, давайте представим, как отменить повторяющийся запрос.
3. Как отменить повторные запросы
Поскольку нам необходимо обработать все запросы, мы можем рассмотреть возможность использования механизма перехватчика Axios для реализации функции отмены повторных запросов. Axios предоставляет перехватчики запросов и перехватчики ответов для разработчиков, и их функции заключаются в следующем:
- Перехватчик запроса. Роль перехватчика этого типа заключается в унифицированном выполнении определенных операций перед отправкой запроса, таких как добавление поля токена в заголовок запроса.
- Перехватчик ответа: функция перехватчика этого типа заключается в единообразном выполнении определенных операций после получения ответа сервера, например, автоматический переход на страницу входа в систему, когда обнаруживается, что код состояния ответа равен 401.
3.1 Определение вспомогательных функций
Прежде чем настраивать перехватчик запросов и перехватчик ответов, Brother Abao сначала определяет 3 вспомогательные функции:
-
generateReqKey
: используется для генерации ключа запроса в соответствии с информацией текущего запроса;
function generateReqKey(config) {
const { method, url, params, data } = config;
return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}
-
addPendingRequest
: используется для добавления информации о текущем запросе в объект pendingRequest;
const pendingRequest = new Map();
function addPendingRequest(config) {
const requestKey = generateReqKey(config);
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
if (!pendingRequest.has(requestKey)) {
pendingRequest.set(requestKey, cancel);
}
});
}
-
removePendingRequest
: Проверить, нет ли повторяющихся запросов, если есть, отменить отправленные запросы.
function removePendingRequest(config) {
const requestKey = generateReqKey(config);
if (pendingRequest.has(requestKey)) {
const cancelToken = pendingRequest.get(requestKey);
cancelToken(requestKey);
pendingRequest.delete(requestKey);
}
}
созданныйgenerateReqKey
,addPendingRequest
а такжеremovePendingRequest
После функции мы можем установить перехватчик запроса и перехватчик ответа.
3.2 Настройка перехватчика запросов
axios.interceptors.request.use(
function (config) {
removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中
return config;
},
(error) => {
return Promise.reject(error);
}
);
3.3 Настройка перехватчика ответов
axios.interceptors.response.use(
(response) => {
removePendingRequest(response.config); // 从pendingRequest对象中移除请求
return response;
},
(error) => {
removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
if (axios.isCancel(error)) {
console.log("已取消的重复请求:" + error.message);
} else {
// 添加异常处理
}
return Promise.reject(error);
}
);
Так как полный пример кода содержит много контента, Brother Abao не будет помещать конкретный код. Заинтересованные партнеры могут посетить следующий адрес, чтобы просмотреть образец кода.
Полный пример кода:gist.GitHub.com/Semelinker/О…
Здесь давайте посмотрим на результаты примера запроса отмены дублирования Axios:
Этот пример предназначен только для проверки того, может ли перехватчик нормально работать.В реальной работе повторяющиеся запросы, вызванные операциями с кнопками, можно контролировать, увеличивая бит состояния. Спасибо "@Bozhishu" за предложение.
Как видно из приведенного выше рисунка, при возникновении дублирующего запроса ранее отправленный и неполный запрос будет отменен. Ниже мы используем блок-схему, чтобы обобщить поток обработки отмены повторных запросов:
Наконец, давайте ответим на вопрос, оставленный ранее, а именноCancelToken
Как работает интерьер?
4. Как работает CancelToken
В предыдущем примере мы сделали это, вызвавCancelToken
конструктор для созданияCancelToken
Объект:
new axios.CancelToken((cancel) => {
if (!pendingRequest.has(requestKey)) {
pendingRequest.set(requestKey, cancel);
}
})
Итак, давайте проанализируемCancelToken
конструктор, который определен вlib/cancel/CancelToken.js
В файле:
// lib/cancel/CancelToken.js
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
executor(function cancel(message) { // 设置cancel对象
if (token.reason) {
return; // Cancellation has already been requested
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
Как видно из приведенного выше кода,cancel
Объект является функцией, когда мы вызываем функцию, она будет созданаCancel
возражать и звонитьresolvePromise
метод. После выполнения этого методаCancelToken
на объектеpromise
атрибут указывает наpromise
Состояние объекта станетresolved
. Итак, какова цель этого? Здесь мы начинаем сlib/adapters/xhr.js
Ответ находится в документации:
// lib/adapters/xhr.js
if (config.cancelToken) {
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) { return; }
request.abort(); // 取消请求
reject(cancel);
request = null;
});
}
После прочтения вышеуказанного контента некоторые друзья могут не очень хорошо понятьCancelToken
Принцип работы, поэтому брат А Бао нарисовал еще одну картинку, чтобы помочь всем понятьCancelToken
Как это работает:
V. Резюме
В этой статье описывается, как отменить повторные запросы в Axios и как работает CancelToken.Следует отметить, что отмененный запрос мог дойти до сервера, в этом случае соответствующий интерфейс сервера необходимо контролировать идемпотентно.. В следующих статьях Brother Abao расскажет, как настроить кэш данных в Axios. Не пропустите, если вам это интересно. Если вы хотите понять структуру и реализацию HTTP-перехватчиков и HTTP-адаптеров в Axios, вы можете прочитатьКакие уроки можно извлечь из проекта 77.9K Axios?Эта статья.
Следуйте «Дорога полного стека», чтобы прочитать 4 бесплатные электронные книги (всего более 30 000 загрузок) и 11 руководств по Vue 3 для продвинутых пользователей.Друзья, которые хотят вместе изучать TS/Vue 3.0, могут добавить Abaoge WeChat —— semlinker.