在 Express 路由器中处理套接字超时

Handling socket time-out in express router

在 express 应用程序中(作为 API 服务器)我想在路由器级别知道当前服务的客户端由于套接字超时而断开连接,并在下次客户端时保持响应发送请求。这个特定的路线有时会导致一些长时间的操作。 处理此类流程的正确方法是什么(无需将客户端切换到轮询)?

首先,要为特定客户端保留响应,您需要某种 server-side 会话对象和相应的客户端 cookie 来存储 client-specific 响应。

然后,您可能需要确定要保留此结果的时间(直到它过时多久?)。

第三,Express默认不会超时客户端请求。因此,除非您在 Express 中设置超时,否则如果您遇到超时,那么它要么来自客户端,要么来自您的托管服务提供商。在某些方面,它来自哪里并不重要。您可以检测到套接字已关闭,但没有发送 Express 请求。请参阅下面的代码了解如何执行此操作。

const kMaxSaveResponseTime = 10 * 60 * 1000; // 10 minutes

app.get("/someRequest", (req, res) => {
    const priorResult = req?.session?.priorResult?.expirationTime;
    if (priorResult && priorResult >= Date.now()) {
        // if there is a prior result that hasn't yet expired, use it
        let data = req.session.priorResult.data;
        delete req.session.priorResult;
        res.send(data);
        return;
    }
    // otherwise calculate new result and attempt to send it
    // simulate some function that takes a long time
    // The setTimeout() here is just to simulate taking awhile
    setTimeout(() => {
        // We have the eventual result here
        let data = someDateWeBuilt;

        // See if the request socket is still alive
        // If not, save the result we just finished calculating
        if (res.socket.destroyed) {
            // client connection has already been killed
            // save the data we have for next connection
            req.session.priorResult = {
                expirationTime: Date.now() + kMaxSaveResponseTime,
                data: data
            };
        } else {
            // connection still alive, send the result
            res.send(data)
        }
    }, 5000);

});

这假设您使用 express-session 作为 server-side 会话状态。它假设客户端已经建立了一个有效的会话。

一般的想法是,您首先检查会话中是否已经存在 non-expired priorResult。如果是这样,您获取该数据,将其从会话中删除并将其作为响应发送。如果没有,你会做任何耗时的事情来计算最终结果,当你最终得到那个结果时,你检查 res.socket.destroyed 看看客户端套接字是否仍然存在。如果不是,则将数据缓存在会话中。如果它还活着,你发送响应。