AyKarsi
AyKarsi

Reputation: 9685

node http-proxy: async modification of request body

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..

Upvotes: 2

Views: 4050

Answers (3)

mh8020
mh8020

Reputation: 1844

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);

Upvotes: 0

Nick Richardson
Nick Richardson

Reputation: 187

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
});

Upvotes: 1

Ovidiu Dolha
Ovidiu Dolha

Reputation: 5423

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.

Upvotes: 2

Related Questions