2

I need to modify the request body asynchronously. Something along the lines of this:

proxy.on('proxyReq', function(proxyReq, req, res, options) {
  if(req.body) {
    new Promise(function(resolve){ 
      setTimeout(function() { // wait for the db to return
        'use strict';
        req.body.text += 'test';
        let bodyData = JSON.stringify(req.body);
        proxyReq.setHeader('Content-Type','application/json');
        proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
        // stream the content
        proxyReq.write(bodyData);
        resolve();
      },1);
    });
  }
});

When I run this I get the error saying cannot modfiy headers once they have been set. Which makes sense.

How can I halt the sending of the request until I'm ready? I've looked at removing various listeners from proxyReq without success..

AyKarsi
  • 9,435
  • 10
  • 54
  • 92

3 Answers3

2

By looking at the source code @-) it seems like it's not really possible because the proxyReq event is sent and then the code moves on.

If it would instead wait for a promise, it would be possible (if you'd return that promise as well).

A minimal fork on this lib could be for example:

// Enable developers to modify the proxyReq before headers are sent
proxyReq.on('socket', function(socket) {
  if(server) { server.emit('proxyReq', proxyReq, req, res, options); }
});

(proxyReq.proxyWait || Promise.resolve())
    .then( ... // rest of the code inside the callback 

And then

proxy.on('proxyReq', function(proxyReq, req, res, options) {
  if(req.body) {
    proxyReq.proxyWait = new Promise(function(resolve){ 
      setTimeout(function() { ...

But depending on your use case, there might be other solutions as well. For example, consider if it's really necessary that you use this proxy library. It You could alternatively use http directly, where you have all the control on the events and callbacks.

Ovidiu Dolha
  • 5,335
  • 1
  • 21
  • 30
  • I've been digging in the source for a while :) I don't think your suggesting will work, because I understand server.emit('proxyReq'.. to be async in itself. So proxyWait will not be present when the code passes (proxyReq.proxyWait || Promise.resolve()) for the first time.. – AyKarsi May 15 '17 at 12:17
  • hmm, isn't the emit the same/similar to nodejs emit, [which is synchronous](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args) - alternativley to the `proxyWait` approach you could use your own emit from the callback to communicate back when ready (e..g `new Promise(...).then(proxyReq.emit('doneProxy'))` and then you wait for this event back in the original source code, but that means you must have a `proxyReq.on('doneProxy', () => // rest of the code)` registered before the actual emit of the `proxyReq` event if that makes sense -I'm pretty sure this is not the best idea:P – Ovidiu Dolha May 15 '17 at 12:29
1

You can set selfHandleResponse: true inside the HttpProxy.createProxyServer. This then allows (and forces) you to handle the proxyRes manually!

const proxy = HttpProxy.createProxyServer({selfHandleResponse: true});
proxy.on('proxyRes', async (proxyReq, req, res, options) => {
  if (proxyReq.statusCode === 404) {
    req.logger.debug('Proxy Request Returned 404');
    const something = await doSomething(proxyReq);
    return res.json(something);
  }
  return x;// return original proxy response
});
Nick Richardson
  • 187
  • 2
  • 9
0

I came here looking for the solution to a slightly different problem: Modifying the request headers (not body) before proxying.

I post this here in case that it is helpful to others. And maybe the code can be adapted to also modify the request body.

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

var proxy = httpProxy.createProxyServer({});

var server = http.createServer(function(req, res) {
    console.log(`${req.url} - sleeping 1s...`);
    setTimeout(() => {
        console.log(`${req.url} - processing request`);
        req.headers['x-example-req-async'] = '456';
        proxy.web(req, res, {
            target: 'http://127.0.0.1:80'
        });
    }, 1000);
});

server.listen(5050);
mh8020
  • 1,784
  • 1
  • 11
  • 14