如何在发送相应响应后立即通过请求中止
Deno.serve
?
我当前的解决方法是在中止
AbortController
之前休眠 1 秒。我已经尝试过queueMicrotask
,但似乎响应不是通过主线程发送的。
这是我的解决方法:
//example.ts
//deno run --allow-net=127.0.0.1 example.ts
const port = 3000;
const hostname = "127.0.0.1";
const ac = new AbortController();
const signal = ac.signal;
let isShuttingDown = false;
const server = Deno.serve(
{ port, hostname, signal },
(req: Request, _info: Deno.ServeHandlerInfo) => {
if (isShuttingDown) {
return new Response("Server is shutting down!", { status: 503 });
}
const url = new URL(req.url);
if (
url.pathname === "/shutdown"
) {
isShuttingDown = true;
// queueMicrotask(()=>{ //does not run after response is sent
// ac.abort();
// });
setTimeout(() => {
ac.abort();
}, 1000); //give client time to receive response
return new Response(null, { status: 202 });
}
return new Response("hello");
},
);
await server.finished;
console.log("server stopped");
还有比等待足够长的超时更好的方法吗?
中添加了一个unstable 方法
Deno.HttpServer
,以方便正常关闭。
shutdown(): Promise<void>
优雅地关闭服务器。将不再接受新连接,同时将允许完成待处理的请求。
我还没有审查源代码实现(所以也许我遗漏了一些东西),但在 服务器处理函数 中使用它目前似乎仍然需要延迟。也许该实现会阻止在调用后立即发送任何新响应 - 文档没有明确说明这一点。
简而言之,您可以在返回响应之前在请求处理程序回调函数中优雅地关闭服务器,如下所示:
function handler() {
queueMicrotask(httpServer.shutdown);
return new Response(/* … */);
}
这是一个完整的可重现示例:
server.ts
:
/// <reference lib="deno.unstable" />
function delay(ms: number): Promise<void> {
return new Promise((res) => setTimeout(res, ms));
}
function createPlainTextResponse(
text: string,
init: ResponseInit = {},
): Response {
const { headers: headersInit, ...rest } = init;
const headers = new Headers(headersInit);
headers.set("Content-Type", "text/plain; charset=utf-8");
return new Response(text, { ...rest, headers });
}
function handleNotFound(): Response {
return createPlainTextResponse("Not Found", { status: 404 });
}
const routeHandlers: Record<string, Deno.ServeHandler> = {
"/hello": () => createPlainTextResponse("Hello world"),
"/shutdown": () => {
queueMicrotask(httpServer.shutdown);
return createPlainTextResponse("Server is shutting down", { status: 202 });
},
};
const handleRequest: Deno.ServeHandler = (request, info) => {
const url = new URL(request.url);
const handler = routeHandlers[url.pathname] ?? handleNotFound;
return handler(request, info);
};
function printStartupMessage({ hostname, port, secure }: {
hostname: string;
port: number;
secure?: boolean;
}): void {
if (!hostname || hostname === "0.0.0.0") hostname = "localhost";
const address =
new URL(`http${secure ? "s" : ""}://${hostname}:${port}/`).href;
console.log(`Listening at ${address}`);
console.log("Use ctrl+c to stop");
}
async function logInfoAndSendTestRequests(
opts: Parameters<NonNullable<Deno.ServeOptions["onListen"]>>[0],
): Promise<void> {
printStartupMessage(opts);
const origin = `http://${opts.hostname}:${opts.port}`;
console.log("Client started");
for (const pathname of ["/hello", "/oops", "/shutdown", "/hello"]) {
try {
await delay(250);
const response = await fetch(`${origin}${pathname}`);
const text = await response.text();
console.log(pathname, response.status, text);
} catch (cause) {
console.error("Caught client exception:", cause);
}
}
console.log("Client stopped");
}
const opts = {
hostname: "localhost",
onListen: logInfoAndSendTestRequests,
port: 3000,
} satisfies Deno.ServeOptions;
const httpServer = Deno.serve(opts, handleRequest);
await httpServer.finished;
console.log("Server stopped");
终端:
% deno --version
deno 1.38.3 (release, aarch64-apple-darwin)
v8 12.0.267.1
typescript 5.2.2
% deno run --unstable --allow-net=localhost:3000 server.ts
Listening at http://localhost:3000/
Use ctrl+c to stop
Client started
/hello 200 Hello world
/oops 404 Not Found
Server stopped
/shutdown 202 Server is shutting down
Caught client exception: TypeError: error sending request for url (http://localhost:3000/hello): error trying to connect: tcp connect error: Connection refused (os error 61)
at async mainFetch (ext:deno_fetch/26_fetch.js:277:12)
at async fetch (ext:deno_fetch/26_fetch.js:504:7)
at async Object.logInfoAndSendTestRequests [as onListen] (file:///Users/deno/so-77547677/server.ts:58:24)
Client stopped
% echo $?
0