http-proxy-middleware

repository·master·Indexed 11 days ago

https://github.com/chimurai/http-proxy-middleware

A Node.js proxy middleware compatible with Express, Connect, Next.js, Hono, and more. Version 4.2.0 provides utilities like createProxyMiddleware for target routing, pathFilter for request narrowing, pathRewrite for URL modification, and responseInterceptor for manipulating response bodies.

Tokens
26.9K
Snippets
99
Records
112
Agent score
90%

What's inside http-proxy-middleware

  1. What is pathFilter and when to use it

    master

    The pathFilter option allows you to narrow down which specific requests should be proxied. The filtering is based on the request.url pathname. In Express, this corresponds to the path relative to the mount-point of the proxy.

    pathFilter is optional. It is particularly useful when you cannot use standard middleware mounting (e.g., app.use('/api', proxy)) to isolate your proxy logic.

  2. Use and define plugins

    master

    Plugins allow you to hook into proxy events. You can provide an array of plugins via the plugins option.

    Creating a plugin

    Use the definePlugin helper to create a plugin. A plugin receives (proxyServer, options) and can subscribe to events on the proxyServer.

    Ejecting default plugins

    By default, http-proxy-middleware includes several plugins. If you want to replace them entirely, set ejectPlugins: true. If you do this, you must manually register your own error handlers (like debugProxyErrorsPlugin) to prevent your server from crashing on proxy errors.

    import { createProxyMiddleware, definePlugin } from 'http-proxy-middleware';
    
    const myPlugin = definePlugin((proxyServer, options) => {
      // plugin implementation
    });
    
    // use configure and use plugin
    createProxyMiddleware({
      target: `http://example.org`,
      plugins: [myPlugin],
    });
    
    // eject default plugins and manually add them back
    import {
      debugProxyErrorsPlugin,
      errorResponsePlugin,
      loggerPlugin,
      proxyEventsPlugin,
    } from 'http-proxy-middleware';
    
    createProxyMiddleware({
      target: `http://example.org`,
      changeOrigin: true,
      ejectPlugins: true,
      plugins: [debugProxyErrorsPlugin, loggerPlugin, errorResponsePlugin, proxyEventsPlugin],
    });
  3. Use responseInterceptor to modify upstream responses

    master

    The responseInterceptor allows you to intercept and modify responses coming from the upstream server.

    Critical Requirement: You must set selfHandleResponse: true in your createProxyMiddleware configuration. If you do not, res.end() may be called automatically by the middleware before your interceptor can finish, leading to errors or unexpected behavior. When selfHandleResponse is true, responseInterceptor handles calling res.end() internally.

    Key Features:

    • Automatic Decompression: Responses compressed with brotli, gzip, deflate, and zstd (requires Node.js >= 22.15.0) are automatically decompressed.
    • Buffer Access: The response is provided as a Node.js buffer, which you can convert to strings, parse as JSON, or process as binary data (e.g., images).
    • Signature: The interceptor function receives (responseBuffer, proxyRes, req, res) and must return the modified content (as a string, buffer, or other compatible type).
    import { createProxyMiddleware, responseInterceptor } from 'http-proxy-middleware';
    
    const proxy = createProxyMiddleware({
      target: 'http://www.example.com',
      selfHandleResponse: true, // REQUIRED
      on: {
        proxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
          // Your logic here
          return responseBuffer;
        }),
      },
    });
  4. Configure `pathRewrite` in v3

    master

    Due to the removal of req.url patching, pathRewrite behavior has changed: it now only rewrites the path after the mount point.

    If you were using pathRewrite to rewrite the basePath (the mount point itself), you should now move that logic into the target URL instead.

    Note: If the proxy is mounted at the root (/), pathRewrite behavior remains unchanged from v2.

    // before
    app.use(
      '/user',
      proxy({
        target: 'http://www.example.org',
        pathRewrite: { '^/user': '/secret' },
      }),
    );
    
    // after
    app.use('/user', proxy({ target: 'http://www.example.org/secret' }));
  5. Handle removed `req.url` patching in v3

    master

    In version 3, the middleware no longer automatically patches req.url. When you mount a proxy on a specific path, that path must now be included in the target URL.

    Example Migration: If you previously mounted on /user with a target of http://www.example.org, you must now include /user in the target.

    // before
    app.use('/user', proxy({ target: 'http://www.example.org' }));
    
    // after
    app.use('/user', proxy({ target: 'http://www.example.org/user' }));
  6. Configure a custom logger in http-proxy-middleware

    master

    You can configure http-proxy-middleware to output information using various logging libraries by passing the logger instance to the logger option in the createProxyMiddleware configuration object. Supported loggers include console, winston, pino, log4js, and bunyan.

    import { createProxyMiddleware } from 'http-proxy-middleware';
    
    const proxy = createProxyMiddleware({
      target: 'http://localhost:3000',
      logger: yourLoggerInstance,
    });
  7. Use a Proxy Table to route based on Host or Path

    master

    A Proxy Table is an object passed to the router option that allows you to map specific request criteria to different targets. The middleware checks for matches based on the following priority/combinations:

    1. Host only: The key is the Host HTTP header.
    2. Path only: The key is the request path.
    3. Host + Path: The key is a combination of the Host header and the request path.

    If no match is found in the table, the request falls back to the default target specified in the middleware options.

    Key Rules:

    • Keys can be just a hostname (e.g., 'integration.localhost:3000').
    • Keys can be just a path (e.g., '/rest').
    • Keys can be a combination (e.g., 'localhost:3000/api').
    import express from 'express';
    import { createProxyMiddleware } from 'http-proxy-middleware';
    
    const proxyTable = {
      'integration.localhost:3000': 'http://localhost:8001', // host only
      'staging.localhost:3000': 'http://localhost:8002', // host only
      'localhost:3000/api': 'http://localhost:8003', // host + path
      '/rest': 'http://localhost:8004', // path only
    };
    
    const options = {
      target: 'http://localhost:8000',
      router: proxyTable,
    };
    
    const myProxy = createProxyMiddleware(options);
    
    const app = express();
    app.use(myProxy);
    
    app.listen(3000);
  8. Implement proxy with Next.js API Routes

    master

    To use the proxy in Next.js, create a singleton middleware instance and then invoke it within a standard Next.js API route handler.

    Note: You must configure the API route with externalResolver: true. If you encounter stalled POST requests, you may need to set bodyParser: false in the route config.

    // /pages/api/users.proxy.ts
    import { createProxyMiddleware } from 'http-proxy-middleware';
    
    export const proxyMiddleware = createProxyMiddleware<NextApiRequest, NextApiResponse>({
      target: 'http://jsonplaceholder.typicode.com',
      changeOrigin: true,
      pathRewrite: {
        '^/api/users': '/users',
      },
    });
    
    // /pages/api/users.ts
    import type { NextApiRequest, NextApiResponse } from 'next';
    import { proxyMiddleware } from './users.proxy';
    
    export default function handler(req: NextApiRequest, res: NextApiResponse) {
      proxyMiddleware(req, res, (result: unknown) => {
        if (result instanceof Error) {
          throw result;
        }
      });
    }
    
    export const config = {
      api: {
        externalResolver: true,
        // bodyParser: false, // Use this to fix stalled POST requests
      },
    };
  9. Modify proxied request headers asynchronously

    master

    Since the proxyReq event handler is synchronous, you cannot directly await inside it to modify request headers. To achieve asynchronous request header modification, apply an asynchronous middleware function before the proxy middleware in your application stack. This middleware can perform async operations and attach data to the req object (e.g., req.locals), which can then be accessed synchronously within the proxyReq handler.

    const entryMiddleware = async (req, res, next) => {
      const foo = await new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve({ da: 'da' });
        }, 200);
      });
      req.locals = {
        da: foo.da,
      };
      next();
    };
    
    const myProxy = createProxyMiddleware({
      target: 'http://www.example.com/api',
      changeOrigin: true,
      selfHandleResponse: true,
      on: {
        proxyReq: (proxyReq, req, res) => {
          // get something async from entry middleware before the proxy kicks in
          console.log('proxyReq:', req.locals.da);
    
          proxyReq.setHeader('mpth-1', req.locals.da);
        },
        proxyRes: async (proxyRes, req, res) => {
          const da = await new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve({ wei: 'wei' });
            }, 200);
          });
    
          res.setHeader('mpth-2', da.wei);
          proxyRes.pipe(res);
        },
      },
    });
    
    app.use('/api', entryMiddleware, myProxy);
  10. Manually subscribe to WebSocket upgrade events

    master

    If you want to support WebSocket upgrades without requiring an initial HTTP request, you can manually subscribe the proxy's upgrade handler to the server's upgrade event. This is done using server.on('upgrade', proxy.upgrade).

    import { createProxyMiddleware } from 'http-proxy-middleware';
    
    const socketProxy = createProxyMiddleware({
      target: 'http://localhost:3000',
      pathFilter: '/socket',
      ws: true,
    });
    
    server.on('upgrade', socketProxy.upgrade); // <-- subscribe to http 'upgrade'
  11. Install the http-proxy-middleware repository for development

    master

    If you want to run the local examples, clone the repository and use the following commands to set up the environment:

    1. Clone the repo: git clone https://github.com/chimurai/http-proxy-middleware.git
    2. Install all dependencies: yarn install:all
    3. Build the project: yarn build
    git clone https://github.com/chimurai/http-proxy-middleware.git
    yarn install:all
    yarn build
  12. Use the v2 to v3 adapter for minimal changes

    master

    If you are migrating from version 2 to version 3, you can use legacyCreateProxyMiddleware to maintain your existing configuration with minimal changes. This adapter will print runtime console messages to guide you through the migration process.

    Note: legacyCreateProxyMiddleware is a temporary solution and will be removed in a future version.

    // before
    const { createProxyMiddleware } = require('http-proxy-middleware');
    createProxyMiddleware(...);
    
    // after
    const { legacyCreateProxyMiddleware } = require('http-proxy-middleware');
    legacyCreateProxyMiddleware(...);