CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-express-http-proxy

Express middleware for proxying HTTP requests to another host and passing the response back to the original caller

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

body-processing.mddocs/

Body Processing Configuration

Control how request bodies are parsed, encoded, and handled during the proxying process. This includes configuration for binary uploads, text encoding, size limits, and compatibility with body-parser middleware.

Capabilities

Parse Request Body

Control whether the proxy middleware parses the request body. This is essential for binary uploads and performance optimization with large payloads.

/**
 * Whether to parse the request body
 * @type {boolean}
 * @default true
 */
parseReqBody?: boolean;

Usage Examples:

const proxy = require('express-http-proxy');

// Disable body parsing for binary uploads
app.use('/upload', proxy('file-server.com', {
  parseReqBody: false // Required for binary uploads
}));

// Default behavior (body parsing enabled)
app.use('/api', proxy('api.example.com', {
  parseReqBody: true // Default value, can be omitted
}));

// Large file handling
app.use('/large-files', proxy('storage.example.com', {
  parseReqBody: false, // Don't hold large files in memory
  limit: '100mb' // This will be ignored when parseReqBody is false
}));

Request as Buffer

Control whether the request body should be encoded as a Node.js Buffer when sending the proxied request.

/**
 * Encode request body as Node Buffer
 * @type {boolean}
 * @default false
 */
reqAsBuffer?: boolean;

Usage Examples:

// Binary data handling
app.use('/binary', proxy('binary-processor.com', {
  reqAsBuffer: true,
  reqBodyEncoding: null // Preserve binary data
}));

// Image upload handling
app.use('/images', proxy('image-service.com', {
  parseReqBody: true,
  reqAsBuffer: true,
  reqBodyEncoding: null // Important for binary image data
}));

Request Body Encoding

Specify the encoding used to decode the request body. This is crucial for handling different types of content correctly.

/**
 * Encoding used to decode request body
 * @type {string|null}
 * @default 'utf-8'
 */
reqBodyEncoding?: string | null;

Usage Examples:

// Default UTF-8 encoding for text
app.use('/text', proxy('text-processor.com', {
  reqBodyEncoding: 'utf-8' // Default value
}));

// Preserve binary data (images, files, etc.)
app.use('/files', proxy('file-handler.com', {
  reqBodyEncoding: null // Preserve as Buffer
}));

// Specific encoding for legacy systems
app.use('/legacy', proxy('legacy-system.com', {
  reqBodyEncoding: 'latin1' // For legacy text encoding
}));

// Binary image uploads
app.use('/images', proxy('image-service.com', {
  parseReqBody: true,
  reqAsBuffer: true,
  reqBodyEncoding: null // Critical for image data
}));

Body Size Limit

Set the maximum allowed size for request bodies. Uses the same format as the bytes.js package.

/**
 * Body size limit
 * @type {string}
 * @default '1mb'
 */
limit?: string;

Usage Examples:

// Small API requests
app.use('/api', proxy('api.example.com', {
  limit: '1mb' // Default value
}));

// Large file uploads
app.use('/upload', proxy('upload-service.com', {
  limit: '50mb' // Allow larger uploads
}));

// Tiny data endpoints
app.use('/tiny', proxy('micro-service.com', {
  limit: '1kb' // Very restrictive
}));

// Video upload service
app.use('/videos', proxy('video-service.com', {
  limit: '500mb',
  parseReqBody: false // Recommended for very large files
}));

Advanced Body Processing Patterns

Binary File Upload Handling

// Complete binary upload configuration
app.use('/upload', proxy('storage-service.com', {
  parseReqBody: false, // Don't parse large binary files
  limit: '100mb', // Set appropriate limit (ignored when parseReqBody is false)
  
  // Handle the raw stream directly
  proxyReqBodyDecorator: function(bodyContent, srcReq) {
    // bodyContent will be the raw stream when parseReqBody is false
    return bodyContent;
  }
}));

Text Content with Custom Encoding

// Legacy system with custom encoding
app.use('/legacy-text', proxy('legacy.example.com', {
  parseReqBody: true,
  reqBodyEncoding: 'latin1',
  reqAsBuffer: false,
  
  proxyReqBodyDecorator: function(bodyContent, srcReq) {
    // Process text with legacy encoding
    const text = bodyContent.toString();
    return text.toUpperCase(); // Example transformation
  }
}));

JSON with Size Validation

// JSON API with custom size limits
app.use('/json-api', proxy('json-service.com', {
  parseReqBody: true,
  reqBodyEncoding: 'utf-8',
  limit: '5mb',
  
  proxyReqBodyDecorator: function(bodyContent, srcReq) {
    try {
      const data = JSON.parse(bodyContent.toString());
      
      // Add validation or transformation
      if (Array.isArray(data) && data.length > 1000) {
        throw new Error('Array too large');
      }
      
      return JSON.stringify(data);
    } catch (error) {
      throw new Error('Invalid JSON: ' + error.message);
    }
  }
}));

Body Parser Compatibility

Correct Middleware Order

const express = require('express');
const bodyParser = require('body-parser');
const proxy = require('express-http-proxy');

const app = express();

// CORRECT: Declare proxy BEFORE body-parser
app.use('/proxy', proxy('example.com'));

// Declare body-parser AFTER proxy
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// Other routes
app.use('/api', otherRoutes);

When Body Parser Must Come First

// If you MUST use proxy after body-parser
const app = express();

// Body parser comes first (unavoidable in some cases)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// Configure proxy to work with pre-parsed body
app.use('/proxy', proxy('example.com', {
  parseReqBody: false, // Critical: don't parse again
  
  proxyReqBodyDecorator: function(bodyContent, srcReq) {
    // Explicitly specify the body to send
    // srcReq.body is already parsed by body-parser
    return JSON.stringify(srcReq.body);
  }
}));

Performance Considerations

Memory Usage

// Memory-efficient configuration for large files
app.use('/efficient', proxy('service.com', {
  parseReqBody: false, // Stream directly, don't buffer
  // limit is ignored when parseReqBody is false
}));

// Memory-intensive configuration (avoid for large files)
app.use('/memory-intensive', proxy('service.com', {
  parseReqBody: true, // Buffers entire body in memory
  limit: '100mb' // Large limit = high memory usage
}));

Streaming vs Buffering

  • parseReqBody: false: Streams request directly to target server (memory efficient)
  • parseReqBody: true: Buffers entire request body in memory (required for modification)

Error Handling

Size Limit Exceeded

When the body size exceeds the limit, express-http-proxy returns a 413 Request Entity Too Large error.

app.use('/protected', proxy('service.com', {
  limit: '1mb'
}));

// Error handling middleware
app.use((error, req, res, next) => {
  if (error.status === 413) {
    res.status(413).json({
      error: 'Request body too large',
      limit: '1mb'
    });
  } else {
    next(error);
  }
});

Encoding Errors

app.use('/safe-encoding', proxy('service.com', {
  reqBodyEncoding: 'utf-8',
  
  proxyReqBodyDecorator: function(bodyContent, srcReq) {
    try {
      // Safe encoding handling
      const text = bodyContent.toString('utf-8');
      return text;
    } catch (error) {
      console.error('Encoding error:', error);
      throw new Error('Invalid character encoding');
    }
  }
}));

docs

body-processing.md

error-handling.md

filtering.md

index.md

network-configuration.md

path-resolution.md

request-modification.md

response-processing.md

tile.json