This article is not a tutorial on how to use http-proxy-middleware. Please also refer to the official tutorial for more information on how to use it.

This article is mainly to record some precautions when using it.

1. can not continue to flow routes

As we use express and other frameworks, we will declare multiple routes, some routes are used to handle business logic, some are to collect relevant information, some are used as interceptors and so on.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { createProxyMiddleware } from 'http-proxy-middleware';
import express from 'express';

const app = express();

app.use('*', createProxyMiddleware());
app.use('*', () => {
  console.log('after createProxyMiddleware'); // 无法输出
});

const port = Number(process.env.PORT) || 3001;
const ip = process.env.IP || '127.0.0.1';
app.listen(port, ip, () => {
  const msg = `⚡️[server]: Server is running at http://${ip}:${port}`;
  console.log(msg);
});

In the above code, after intercepting the request for *, the subsequent routing service will not be executed. So some processing of this route should be done before http-proxy-middleware.

As we can see from the source code, createProxyMiddleware()returns a middleware method, which is a method for handling the route.

1
2
3
4
5
// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/index.ts#L4
export function createProxyMiddleware(options: Options): RequestHandler {
  const { middleware } = new HttpProxyMiddleware(options);
  return middleware;
}

And as you can see in middlware’s method ↓, if the proxy process is normal, the next() logic will not be executed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// https://github.com/chimurai/http-proxy-middleware/blob/35ac1dbd29ff0953f978373dd6add081819087de/src/http-proxy-middleware.ts#L40
export class HttpProxyMiddleware {
  public middleware: RequestHandler = async (req, res, next?) => {
    if (this.shouldProxy(this.proxyOptions.pathFilter, req)) {
      try {
        const activeProxyOptions = await this.prepareProxyRequest(req);
        debug(`proxy request to target: %O`, activeProxyOptions.target);
        this.proxy.web(req, res, activeProxyOptions);
      } catch (err) {
        next && next(err);
      }
    } else {
      next && next();
    }
  }
}

Therefore, subsequent routes will not receive further requests.

2. onProxyRes cannot handle data with content-length 0

We can process the fetched data twice in onProxyRes and then return it. As in the official example intercept-and-manipulate-responses we can replace Hello with GoodBye.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * IMPORTANT: avoid res.end being called automatically
   **/
  selfHandleResponse: true, // res.end() will be called internally by responseInterceptor()

  /**
   * Intercept response and replace 'Hello' with 'Goodbye'
   **/
  on: {
    proxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
      const response = responseBuffer.toString('utf8'); // convert buffer to string
      return response.replace('Hello', 'Goodbye'); // manipulate response and return the result
    }),
  },
});

However, if there is no content-length field in the response header of the data returned from the proxy forwarding address, or if the value of the field is 0, the responseBuffer in onProxyRes is empty and the data cannot be processed.

For example, some CDNs or COSs that use chunked encoding (transfer-encoding: chunked) for fast response, usually do not have the content-length field when returning data.