HTTP Proxy Middleware Response Body Extractor
The `http-proxy-middleware-body` package, currently at version `1.0.0` (last published three years ago), provides a utility function to capture and process the response body from proxied requests when using `http-proxy-middleware`. This is particularly useful for scenarios where introspection or modification of the proxy's response payload is required, such as error handling, token expiration checks, or data transformation before sending the response back to the client. While `http-proxy-middleware` itself focuses on proxying, this package extends its capabilities by exposing the `onProxyRes` event's full response data stream, enabling developers to parse JSON or other raw body formats by buffering the entire stream. Its release cadence is inactive, as `1.0.0` is the current and seemingly only major version. It differentiates itself by offering a simple way to access the full response body, a feature that the core `http-proxy-middleware` API did not directly provide in early versions, though newer versions of `http-proxy-middleware` now offer `responseInterceptor` for similar functionality.
Common errors
-
SyntaxError: Unexpected token < in JSON at position 0
cause The response body being parsed by `JSON.parse` is not valid JSON. This often happens when a non-JSON response (e.g., HTML, plain text, or an error page) is received but treated as JSON.fixAlways wrap `JSON.parse` calls in a `try...catch` block. Inspect the `rawBody` content (e.g., log it) before parsing to understand its format. Check `proxyRes.headers['content-type']` to confirm if the response is actually 'application/json' before attempting to parse it. -
TypeError: getBody is not a function
cause The `getBody` function was not correctly imported or required. This typically happens with incorrect CommonJS `require` syntax (e.g., `const { getBody } = require(...)` instead of `const getBody = require(...)`) if `getBody` is a default export, or a mixup between CommonJS and ESM.fixEnsure you are using the correct `require` statement for CommonJS: `const getBody = require('http-proxy-middleware-body');`. For ESM, use `import getBody from 'http-proxy-middleware-body';`. -
ERR_STREAM_PREMATURE_CLOSE
cause This error might occur if the response stream (`proxyRes`) is being read or consumed by another part of your application or another middleware before `http-proxy-middleware-body` attempts to process it.fixEnsure that `http-proxy-middleware-body`'s `getBody` function is the *only* handler attempting to read the `proxyRes` stream. If other middlewares or custom `onProxyRes` logic also access the stream, they might interfere. Consider the order of middleware execution or consolidate stream handling.
Warnings
- breaking This package (`http-proxy-middleware-body`) is likely incompatible with `http-proxy-middleware` versions that have breaking changes to the `onProxyRes` signature or streaming behavior. Given `http-proxy-middleware` has undergone several major versions and introduced `responseInterceptor` since, this package might not work as expected with newer `http-proxy-middleware` versions (e.g., v3+ or v4+).
- gotcha This package buffers the entire response body in memory. For very large response payloads, this can lead to high memory consumption and potential performance issues, especially under heavy load. Ensure that the expected response sizes are manageable or implement additional safeguards.
- deprecated `http-proxy-middleware-body` has not been updated in over three years and appears to be in maintenance mode or abandoned. Its parent library, `http-proxy-middleware`, is actively developed and has introduced `responseInterceptor` which can achieve similar outcomes directly. Relying on an unmaintained package can introduce security risks or compatibility issues with newer Node.js versions or other dependencies.
- gotcha The package currently uses CommonJS `require` syntax in its examples and likely does not officially support ESM out of the box. With the Node.js ecosystem shifting towards ESM, and `http-proxy-middleware` itself moving to ESM-only in future major versions (v4+), this can lead to compatibility challenges in modern ESM-only projects.
Install
-
npm install http-proxy-middleware-body -
yarn add http-proxy-middleware-body -
pnpm add http-proxy-middleware-body
Imports
- getBody
import { getBody } from 'http-proxy-middleware-body'; // getBody is likely a default export in CJS contexts.import getBody from 'http-proxy-middleware-body'; // ESM const getBody = require('http-proxy-middleware-body'); // CommonJS - createProxyMiddleware
const createProxyMiddleware = require('http-proxy-middleware'); // Incorrect for named export.import { createProxyMiddleware } from 'http-proxy-middleware'; // ESM const { createProxyMiddleware } = require('http-proxy-middleware'); // CommonJS
Quickstart
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const getBody = require('http-proxy-middleware-body');
const app = express();
const PORT = 3000;
const TARGET_URL = process.env.PROXY_TARGET_URL || 'http://localhost:3001';
app.use('/api', createProxyMiddleware({
target: TARGET_URL,
changeOrigin: true,
onProxyRes: (proxyRes, req, res) => getBody(res, proxyRes, rawBody => {
if (!rawBody) {
console.log('No raw body received or it was empty.');
// Ensure the original response still flows if no body to process
return;
}
try {
const body = JSON.parse(rawBody);
console.log('Intercepted proxy response body:', body);
// Example: Modify response based on content
if (body && body.code === 'TOKEN_EXPIRED_CODE') {
console.warn('Token expired detected! Handling...');
// In a real app, you might redirect, refresh token, or modify response status
res.statusCode = 401; // Unauthorized
res.statusMessage = 'Token Expired';
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'Authentication required. Please log in again.' }));
return;
}
// If not handled, simply send the raw body back
res.setHeader('Content-Type', proxyRes.headers['content-type'] || 'application/json');
res.end(rawBody);
} catch (e) {
console.error('Error parsing proxy response body:', e);
// Fallback: send original raw body or an error response
res.setHeader('Content-Type', proxyRes.headers['content-type'] || 'text/plain');
res.end(rawBody || 'Error processing response.');
}
})
}));
// A simple target server for demonstration
app.get('/target', (req, res) => {
res.json({ message: 'Hello from target!', code: 'SUCCESS' });
});
app.get('/target-expired', (req, res) => {
res.json({ message: 'Your token has expired.', code: 'TOKEN_EXPIRED_CODE' });
});
app.listen(PORT, () => {
console.log(`Proxy server listening on port ${PORT}`);
console.log(`Target server running on ${TARGET_URL}. Use /api/target or /api/target-expired`);
});
// To run this example, create a target server (e.g., on port 3001)
// const express = require('express');
// const app = express();
// app.listen(3001, () => console.log('Target server on 3001'));
// app.get('/', (req, res) => res.json({ message: 'Default target response' }));
// app.get('/target', (req, res) => res.json({ message: 'Hello from target!', code: 'SUCCESS' }));
// app.get('/target-expired', (req, res) => res.json({ message: 'Your token has expired.', code: 'TOKEN_EXPIRED_CODE' }));