Modify Request body and then proxying in Node.js

11,353

The real problem is that there is an integration problem between modules body-parser and http-proxy, as stated in this thread.

One solution is to configure body-parser after http-proxy. If you can't change the order of the middleware (as in my case), you can restream the parsed body before proxying the request.

// restream parsed body before proxying
proxy.on('proxyReq', function(proxyReq, req, res, options) {
    if (req.body) {
        let bodyData = JSON.stringify(req.body);
        // if content-type is application/x-www-form-urlencoded -> we need to change to application/json
        proxyReq.setHeader('Content-Type','application/json');
        proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
        // stream the content
        proxyReq.write(bodyData);
    }
}
Share:
11,353
riccardo.cardin
Author by

riccardo.cardin

Computer science addicted.

Updated on June 16, 2022

Comments

  • riccardo.cardin
    riccardo.cardin almost 2 years

    I am a relative newbie of Node.js. It been two days that I am trying to modify the body of a Request in Node.js and then forwarding it. For proxying I am using http-proxy module.

    What I have to do is to intercept the password of a user inside a JSON object, encrypting it and set the new encrypted password inside the request body.

    The problem is that every time I try to collect the request body I consume it (i.e. using body-parser). How can I accomplish this task? I know that the Request in node is seen has a stream.

    For sake o completeness, I am using express to chain multiple operation before proxying.

    EDIT

    The fact that I have to proxy the request is not useless. It follows the code that I am trying to use.

    function encipher(req, res, next){
        var password = req.body.password;
        var encryptionData = Crypto().saltHashPassword(password);
        req.body.password = encryptionData.passwordHash;
        req.body['salt'] = encryptionData.salt;
        next();
    }
    
    server.post("/users", bodyParser.json(), encipher, function(req, res) {
        apiProxy.web(req, res, {target: apiUserForwardingUrl});
    });
    

    The server (REST made by Spring MVC) give me the exception Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: null

  • riccardo.cardin
    riccardo.cardin over 7 years
    Have I to chain body-parser first? Beacuse I noticed that it consumes the request.
  • Steeve Pitis
    Steeve Pitis over 7 years
    You have to use body-parser in your express configuration like : app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json());
  • riccardo.cardin
    riccardo.cardin over 7 years
    And it does not consume the request? Will be it available to the next middleware?
  • Steeve Pitis
    Steeve Pitis over 7 years
    bodyParser will transform every request of your server, then in every middleware you will be able to do what you want with the req.body
  • Steeve Pitis
    Steeve Pitis over 7 years
    Try to log your req.body before calling apiProxy, and give us this log.
  • Lane Rettig
    Lane Rettig almost 7 years
    This gives me the error Can't set headers after they are sent.. Cf. github.com/nodejitsu/node-http-proxy/issues/1168 and github.com/nodejitsu/node-http-proxy/issues/908.
  • thetallweeks
    thetallweeks about 5 years
    Just in case it is helpful for others: For me, I was adding more info to the payload so updating the content-length was very important. I also had to include proxyReq.end() after proxyReq.write() or the request seemed to close without any indication of why.
  • Chris Jager
    Chris Jager over 3 years
    Be careful with if (req.body), since {} is 'truthy'. Better to check on props in body object: if (!!req.body && Object.keys(req.body).length > 0)