node.jsnode-requestnode-http-proxyhttp-proxy-middleware

How to make a bocking Request in NodeJS inside a http-proxy-middleware function?


I have a proxy server which modifies a specific type of POST Request before forwarding it to the Server.

The Modification requires me to make a request to another server in order to get the new value that will be put in place of the old one in the POST Request.

I can't get http-proxy-middleware's onProxyReq function to block until I get the new value.

Anything will help. Thanks.

Code:

const options = {
    target: 'http://localhost:8998',
    changeOrigin: true,
    onProxyReq: (proxyReq, req, res) => {
        if (req.path === '/batches' && req.body && req.body.file) {
            request.post('MAKES REQUEST TO ANOTHER SERVER FOR NEW VALUE',{json: {}},(error,res,body)=>{
                req.body.url=body.url;
            });
            const bodyData = JSON.stringify(req.body);
            proxyReq.setHeader('Content-Type', 'application/json');
            proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
            proxyReq.write(bodyData);
        }else{
            const bodyData = JSON.stringify(req.body);
            proxyReq.setHeader('Content-Type', 'application/json');
            proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
            proxyReq.write(bodyData);
        }
    },
};

app.use(createProxyMiddleware(options));

The problem is that the POST request is forwarded before the new value can be received from the request.post operation.


Solution

  • I think this can be solved by using another middleware before the proxy-middleware. In this additional middleware-handler you can check whether to make the external request or not and assign the new url to the req.body. Then, in the onProxyReq you just check if the req.body was altered and recalculate the content-length in that case. Something like (note I'm using superagent as request has been deprecated):

    const superagent = require('superagent');
    
    app.use('/batches', async (req, res, next) => {
        if(req.body && req.body.file) {
           const resp = await superagent('http://your-other-host');
           req.body.url = resp.body.url;
        }
        next();
    });
    
    app.use(createProxyMiddleware(options));
    

    Then in your proxy-config you can do:

    const options = {
        target: 'http://localhost:8998',
        changeOrigin: true,
        onProxyReq: (proxyReq, req, res) => {
            if (req.path === '/batches' && req.body && req.body.file) {
                const bodyData = JSON.stringify(req.body);
                proxyReq.setHeader('Content-Type', 'application/json');
                proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
                proxyReq.write(bodyData);
            }
        },
    };