Express HTTP Proxy Middleware Fork
express-http-proxy-2 is an HTTP proxy middleware for the Express.js framework, designed to forward incoming requests to a specified target host and stream the responses back. This package is a community-maintained fork of the original `express-http-proxy` library, specifically created to address critical bugs, such as issue #509, and to provide comprehensive TypeScript type definitions, making it more robust for modern JavaScript and TypeScript projects. Currently at version 1.1.0, its release cadence is tied to bug fixes and feature enhancements derived from the community's needs, rather than a fixed schedule. Key differentiators include built-in support for streaming requests and responses, the ability to use Promises for asynchronous hooks, and flexible host selection which can be a static string or a dynamic function evaluated per request. It seamlessly integrates into Express applications, offering various configuration options to customize request path resolution, header manipulation, and conditional proxying.
Common errors
-
TypeError: proxy is not a function
cause Attempting to use `express-http-proxy-2` with an incorrect import style, often mixing CommonJS `require` with ESM default import assumptions, or vice-versa.fixFor CommonJS, use `const proxy = require('express-http-proxy-2');`. For ESM, use `import proxy from 'express-http-proxy-2';`. Ensure your `tsconfig.json` or build setup is correctly configured for your module system. -
Error: Can't set headers after they are sent.
cause This typically occurs in Express middleware when a response is sent multiple times or headers are attempted to be modified after the response stream has started. This can happen if a proxy hook (e.g., `userResDecorator` or `proxyErrorHandler`) explicitly sends a response and then Express tries to send another, or if promises in hooks are not handled correctly.fixReview any custom hooks (e.g., `proxyErrorHandler`, `userResDecorator`) to ensure they handle errors or final responses without inadvertently calling `res.send()` or `res.end()` more than once, or after the proxy has already begun sending data. -
Proxy requests are not reaching the target server, or receive unexpected 404/500 errors from the target.
cause This often points to an issue with `proxyReqPathResolver` modifying the path incorrectly, `filter` blocking requests, or an invalid `host` being provided to the proxy.fixFirst, verify the `host` argument is correct and accessible. Then, meticulously debug `proxyReqPathResolver` by logging the `req.url` and the `return` value to ensure the target path is constructed as expected. Check if the `filter` option is unintentionally blocking requests.
Warnings
- deprecated The `forwardPath` and `forwardPathAsync` options are deprecated. Use `proxyReqPathResolver` for all path manipulation needs.
- gotcha When using `body-parser` or similar middleware that parses request bodies, it must be declared *after* `express-http-proxy-2` for a given route. If `body-parser` runs first, it may consume or modify the request body, preventing `express-http-proxy-2` from correctly forwarding the original POST/PUT payload to the target server.
- gotcha Streaming of request and response bodies is disabled if you define certain response modifiers like `userResDecorator`, `userResHeaderDecorator`, or `maybeSkipToNext`. When these hooks are present, the entire request/response body must be buffered in memory, which can lead to performance issues and increased memory consumption with large payloads.
Install
-
npm install express-http-proxy-2 -
yarn add express-http-proxy-2 -
pnpm add express-http-proxy-2
Imports
- proxy
const proxy = require('express-http-proxy-2').default;import proxy from 'express-http-proxy-2';
- ProxyOptions
import { ProxyOptions } from 'express-http-proxy-2';import type { ProxyOptions } from 'express-http-proxy-2'; - proxy
const proxy = require('express-http-proxy-2');
Quickstart
import express from 'express';
import proxy from 'express-http-proxy-2';
const app = express();
const PORT = 3000;
// Configure the proxy middleware for requests to '/api'
// These requests will be forwarded to 'https://jsonplaceholder.typicode.com'
// and rewritten to remove '/api' from the path.
app.use('/api', proxy('https://jsonplaceholder.typicode.com', {
proxyReqPathResolver: (req) => {
// Example: change /api/users to /users
const originalPath = req.url;
const updatedPath = originalPath.replace('/api', '');
console.log(`Proxying request: ${originalPath} -> ${updatedPath}`);
return updatedPath;
},
userResDecorator: (proxyRes, proxyResData) => {
// Optional: modify the response data from the proxied server
console.log('Received response from proxy target.');
const data = JSON.parse(proxyResData.toString('utf8'));
// Add a custom header to the response indicating it was proxied
proxyRes.headers['x-proxied-by'] = 'express-http-proxy-2';
return JSON.stringify({ ...data, proxied: true });
}
}));
// A simple health check route for the Express server itself
app.get('/health', (req, res) => {
res.send('Server is healthy!');
});
app.listen(PORT, () => {
console.log(`Express server listening on http://localhost:${PORT}`);
console.log('Test proxy: curl http://localhost:3000/api/todos/1');
console.log('Test local: curl http://localhost:3000/health');
});