En la aplicación Express (que actúa como servidor API), me gustaría saber en el nivel del enrutador que el cliente que se está sirviendo actualmente se desconectó debido al tiempo de espera del socket y mantener la respuesta para la próxima vez que el cliente envíe la solicitud. Esta ruta específica a veces conduce a alguna operación larga. ¿Cuál sería la forma correcta de manejar dicho flujo (sin cambiar el cliente a sondeo)?
En primer lugar, para mantener una respuesta para un cliente específico, necesitará algún tipo de objeto de sesión del lado del servidor y la cookie de cliente correspondiente para almacenar la respuesta específica del cliente.
Luego, probablemente necesite determinar una cantidad de tiempo durante la cual desea mantener este resultado (¿cuánto tiempo hasta que se vuelva obsoleto?).
En tercer lugar, Express de forma predeterminada no agota el tiempo de espera de las solicitudes de los clientes. Entonces, a menos que establezca un tiempo de espera en Express, si obtiene un tiempo de espera, entonces proviene del cliente o de su proveedor de alojamiento. De alguna manera, realmente no importa de dónde venga. Puede detectar que el socket se ha cerrado, pero no se ha enviado ninguna solicitud Express. Vea el código a continuación para saber cómo hacerlo.
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); });
Esto supone que está utilizando express-session
para el estado de sesión del lado del servidor. Asume que el cliente ya ha establecido una sesión válida.
La idea general es que primero verifique si ya hay un resultado previo no vencido en la sesión. Si es así, toma esos datos, los elimina de la sesión y los envía como respuesta. De lo contrario, haga cualquier cosa que le lleve mucho tiempo para calcular el resultado final y cuando finalmente tenga ese resultado, verifique res.socket.destroyed
para ver si el socket del cliente todavía está activo o no. Si no es así, almacena en caché los datos en la sesión. Si todavía está vivo, envías la respuesta.