Express Request Timeout Middleware
raw JSON →This package, `timeout-middleware` (current version 0.6.1), provides an Express.js middleware designed to gracefully handle slow requests by enforcing a response timeout. It intercepts `res.status`, `res.sendStatus`, and `res.send` methods, checking a `res.timedout` flag before allowing further modifications to the response. Upon timeout, if headers have not yet been sent, it automatically sets the response status to 503 (Service Unavailable) and sends a 'Request Timeout' message. This approach differs from alternatives like `connect-timeout` which require manual `haltOnTimedout` checks after every middleware in the chain. The library aims for a more 'DRY' (Don't Repeat Yourself) implementation by wrapping the core response methods, preventing accidental operations on a timed-out request. As a pre-1.0 version, future API changes are possible, and its release cadence is not explicitly defined in the provided information.
Common errors
error Unhandled 'error' event ↓
res object within your middleware or a global Express error handler: res.on('error', (err) => { console.error('Response error:', err); }); error Error: Can't set headers after they are sent. ↓
if (res.timedout || res.headersSent) return; before attempting to send a response or set headers. This ensures that operations only proceed if the response is still open. Warnings
breaking This package is currently at version 0.6.1, indicating it is pre-1.0. The API surface or core behavior may undergo breaking changes in future minor or major releases before a stable 1.0 version is reached. ↓
gotcha The middleware achieves its 'DRY' approach by wrapping and overriding `res.status`, `res.sendStatus`, and `res.send`. If other middleware or application code attempts to directly access or cache the *original* `res` methods after `timeout-middleware` has been applied, it might bypass the timeout check, leading to unexpected behavior or attempts to write to a timed-out response. ↓
gotcha As `http.ServerResponse` (which Express `res` extends) is an EventEmitter, failure to add a listener for the `error` event can cause the Node.js process to crash if an error occurs during the response lifecycle. The README explicitly mentions this. ↓
Install
npm install timeout-middleware yarn add timeout-middleware pnpm add timeout-middleware Imports
- default wrong
const timeout = require('timeout-middleware');correctimport timeout from 'timeout-middleware'; - timeout wrong
import { timeout } from 'timeout-middleware';correctimport timeout from 'timeout-middleware'; app.use(timeout(30000));
Quickstart
import express from 'express';
import timeout from 'timeout-middleware';
// In a real application, you'd install and use these
// For demonstration, we'll mock them or simply omit them if not critical to timeout behavior
// import bodyParser from 'body-parser';
// import cookieParser from 'cookie-parser';
const app = express();
// Apply the timeout middleware globally with a 2-second timeout
app.use(timeout(2000));
// Simulate body-parser and cookie-parser if needed (or install them)
// app.use(bodyParser.json());
// app.use(cookieParser());
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.get('/slow', (req, res) => {
// Simulate a slow operation that exceeds the timeout
setTimeout(() => {
// This will not send 'Too late!' because the timeout middleware intercepted res.send
// and marked res.timedout = true, returning res instead of calling the original send.
res.send('Too late! This should not be sent.');
}, 5000); // 5 seconds, which is longer than the 2-second timeout
});
app.get('/fast', (req, res) => {
setTimeout(() => {
res.status(200).send('This was fast enough.');
}, 500); // 0.5 seconds, which is faster than the 2-second timeout
});
// It's crucial to handle the 'error' event on the response object
// to prevent Node.js from crashing if an unhandled error occurs.
app.use((err, req, res, next) => {
console.error(err);
if (res.headersSent) {
return next(err); // Delegate to default Express error handler if headers were already sent
}
res.status(500).send('Something broke!');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log('Try accessing /slow and /fast routes.');
});