http-party / node-http-proxy

A full-featured http proxy for node.js
https://github.com/http-party/node-http-proxy
Other
13.95k stars 1.98k forks source link

Alternatives to http-proxy #1687

Open paulrutter opened 2 weeks ago

paulrutter commented 2 weeks ago

I've been using this module for a long time for http proxying, but since it's no longer maintained i was looking into alternatives. For what it's worth, sharing my findings here.

Using node basic modules

My usecase: i have a expressjs app for which i want to proxy all requests to a Node process running on the same machine, on a different port. This code snippet shows how to proxy request/response including error handling.

const stream = require('stream');
const util = require('util');
const pipeline = util.promisify(stream.pipeline);

// proxyPort, req and res are passed here
// proxyPort: 5000
// req: incoming expressjs request
// res: incoming expressjs response

// custom agent if needed
const proxyAgent = new http.Agent({
  keepAlive: global.PROXY_CONFIG.useKeepAlive,
  maxSockets: global.PROXY_CONFIG.maxSockets
});

// copy over url, method and headers here
const requestOptions = {
  hostname: "localhost",
  port: proxyPort,
  path: req.url,
  method: req.method,
  agent: proxyAgent ,
  headers: req.headers
};

// create the proxy request 
const proxyReq = http.request(requestOptions, async (proxyRes) => {
  // Proxy response headers
  for (const headerName of Object.keys(proxyRes.headers)) {
    res.setHeader(headerName, proxyRes.headers[headerName]);
  }

  // Proxy response status code and message
  res.statusCode = proxyRes.statusCode;
  res.statusMessage = proxyRes.statusMessage;

  // send the response body of the proxied response to the origin response 
  try {
    await pipeline(proxyRes, res);
  } catch (err) {
    // add error handling here or log it at least
   res.send(500).end();
  } finally {
    // proxy is done here, log it?
  }
});

// Proxy the request body
try {
  await pipeline(req, proxyReq);
} catch (error) {
  // add error handling here or log it at least
  res.send(500).end();
} finally {
    // The request body is fully proxied here, if you want to do anything with this information
}

This snippet doesn't offer everything this module offers, but it's easily extendable to add features like adding/removing headers from the request or response. It's all plain node code, no additional module involved.

Other proxy modules or ways to do it

I hope this is helpful to others moving away from http-proxy.

med8bra commented 1 week ago

Thanks @paulrutter for this snippet, I was looking into migrating some old code too, and I came up with this using fetch API

async function handler(req: Request): Promise<Response> {
  const parsedUrl = new URL(req.url);
  // transform request
  parsedUrl.host = API_HOST;

  // add forwarded headers
  req.headers.append("x-forwarded-for", req.headers.get("host") ?? DEFAULT_HOST);

  // fetch should handle pipeing ReadStream/WriteStream
  return fetch(new Request(parsedUrl, req));
}

It's pretty simple, but I believe its extendable too to add extra pre/post processing if needed. Currently I'm using this only for dev.

paulrutter commented 1 week ago

@med8bra thanks, that seems pretty easy as well. It doesn't pipe the proxied response (headers, statusCode, body) though, but that could be added probably.

paulrutter commented 1 week ago

Another thing to handle in my code snippet would be request timeout and set-cookie headers, which would need to be rewritten (if cookies are relevant to the proxy). Http-proxy does both as well.