http-party/node-http-proxy

Proper way to handle error

pkropachev opened this issue · 2 comments

Hi!

I'm trying to handle error proxy.on('error', ...), but for some reason writeHead() method is not available for response.

image

Could you please advice what proper way to handle error, e.g. in case target is not available?

import { program, InvalidArgumentError } from 'commander';
import httpProxy from 'http-proxy';
import express from 'express';

function checkPort(value: string) {
  const parsedValue = +value;
  if (isNaN(parsedValue)) {
    throw new InvalidArgumentError('Invalid int value.');
  }
  return parsedValue;
}

program
  .option('-b ,--bind <address>', 'bind to this address (default: all interfaces)')
  .option('-v ,--verbose', 'be verbose')
  .argument('[port]', 'bind to this port', checkPort, 8000)
  .allowExcessArguments(false)
  .parse(process.argv);

const opts = program.opts();
const [port] = program.processedArgs;

const proxy = httpProxy.createProxyServer({});

proxy.on('proxyReq', (proxyReq, req) => {
  console.log(`==> Request: ${req.socket.remoteAddress} - - "${req.method} ${req.url} HTTP/${req.httpVersion}"`);
  if (opts.verbose) {
    console.log('Headers:\n', JSON.stringify(req.headers, null, 2));
  }

  proxyReq.setHeader('User-Agent', 'http-proxy/1.0.0'); // Override User-Agent

  console.log(`<== Request: ${proxyReq.host} - - "${proxyReq.method} ${proxyReq.path}"`);
  if (opts.verbose) {
    console.log('Headers:\n', JSON.stringify(proxyReq.getHeaders(), null, 2));
    console.log(proxyReq);
  }
});

proxy.on('proxyRes', (proxyRes) => {
  console.log(
    `==> Response: ${proxyRes.socket.remoteAddress} - - code ${proxyRes.statusCode}, message ${proxyRes.statusMessage}`,
  );
  if (opts.verbose) {
    console.log('Headers:\n', JSON.stringify(proxyRes.headers, null, 2));
  }
});

proxy.on('error', (err, res) => {
  console.log('Error:', err.message);
  // Handle error here, send response to requester
});

const app = express();

app
  .get('*', (req, res) => {
    const origin_url = new URL(req.url).host;
    proxy.web(req, res, { target: `${req.protocol}://${origin_url}` });
  })
  .listen(port, opts.bind);

const host = opts.bind ? opts.bind : '::';
console.log(`Serving HTTP proxy on ${host} port ${port} ...`);

Thanks!

I think the res parameter is the 3rd parameter in the error callback (not the 2nd):

proxyServer.on('error', (error, req, res) => {
  if (res instanceof ServerResponse) {
    res.writeHead(502, {
      'Content-Type': 'text/plain',
    });
  }
  res.end('Something went wrong while proxying the request.');
});

The typings for this library (@types/http-proxy) indicate that the res param is type ServerResponse<IncomingMessage> | net.Socket, and I assume it will never actually be a Socket unless ws is set to true, but I added the instanceof check in my case so typescript wouldn't complain

Thanks @mikejpeters for your reply! Yes, I did it in the same way.

proxy.on('error', (err, _req, unknownRes) => {
  console.log('Error:', err.message);
  const res = unknownRes as ServerResponse;
  res.writeHead(500, { 'Content-Type': 'text-plain' });
  res.end(err.message);
});