Поведение отмены запроса в Deno.serve
Deno.serve исторически вызывал событие abort у AbortSignal запроса (request.signal) каждый раз, когда запрос завершался, в том числе когда ваш обработчик возвращал успешный ответ. Сигнал должен был указывать на то, что клиент отключился (например, соединение было закрыто до отправки ответа), но на практике он также срабатывал при каждом успешном ответе.
Это поведение называется «устаревшей отменой» и сегодня включено по умолчанию. Флаг --unstable-no-legacy-abort включает исправленное поведение, которое станет поведением по умолчанию в одном из следующих выпусков.
Почему поведение меняется
Поскольку сигнал отменялся при успешном завершении, код, отслеживающий request.signal, не мог отличить ситуацию «клиент отключился» от ситуации «ответ был доставлен без проблем». Это нарушает работу ряда распространённых библиотек, в первую очередь HTTP-прокси для Node.js, таких как http-proxy и http-proxy-middleware (используемой, помимо прочего, Vite), которые воспринимают отмену на стороне вышестоящего сервера как настоящую ошибку и сообщают о ложной ошибке.
Дополнительные сведения см. в задачах #28850 и #29111.
Новое поведение
Если включён --unstable-no-legacy-abort, request.signal отменяется только тогда, когда клиент действительно отменяет запрос или соединение теряется до полной отправки ответа. Успешный ответ больше не вызывает отмену.
Deno.serve((req) => {
req.signal.addEventListener("abort", () => {
// With --unstable-no-legacy-abort this only runs on a real client
// disconnect, not on every successful response.
console.log("client went away");
});
return new Response("hello");
});
Как определить, что запрос полностью доставлен
Если вы использовали устаревшую отмену, чтобы узнать, что ответ был полностью отправлен, вместо этого используйте промис completed из второго аргумента обработчика (ServeHandlerInfo). Это предусмотренный способ отслеживания доставки, не зависящий от режима:
Deno.serve((req, info) => {
info.completed
.then(() => {
// The response, including a streaming body, was sent successfully.
console.log("response fully delivered");
})
.catch((err) => {
// Delivery failed partway through (client disconnected, write error, ...).
console.error("response was not sent successfully:", err);
});
return new Response(someStream);
});
info.completed:
- выполняется, когда ответ (включая потоковое тело) отправлен клиенту, и
- отклоняется, если доставка не удалась до завершения.
Промис создаётся лениво, поэтому обработчики, которые никогда не читают info.completed, не несут дополнительных затрат.
Переход на новое поведение
-
Включите флаг на время тестирования:
›_deno run --unstable-no-legacy-abort main.tsили укажите его в
deno.json:deno.json{ "unstable": ["no-legacy-abort"] } -
Используйте
request.signalтолько для отмены, а логику завершения и очистки перенесите наinfo.completed(или в путь возврата обработчика).
После перехода на новое поведение ваш код продолжит работать без изменений, когда оно станет поведением по умолчанию.
Последнее обновление:
© 2018–2025 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/reference/deno_serve_legacy_abort