6

I have a node/express proxy setup using http-proxy-middleware to route requests to a java-tomcat web service (proxy target).

I need to inject POST form data into the request rawbody with a context-type of "application/x-www-form-urlencoded" prior to forwarding the request to the proxy target. The proxy response will need to have the same post parameters removed prior to sending the response to the client.

I have used a number of different proxies include http-proxy, http-proxy-middleware, node-proxy, and express-proxy but none of these modules appear to have a solution available that allows for POST parameter manipulation

This question was originally posted on https://github.com/chimurai/http-proxy-middleware/issues/61#issuecomment-205494577

'use strict';

var express = require('express');
var router = express.Router();
//var request = require("request");

var proxy_filter = function (path, req) {
    return path.match('^/report') && ( req.method === 'GET' ||    req.method === 'POST' );
};

var proxy_options = {
    target: 'http://localhost:8080',
    logLevel: 'debug',
    //logProvider:
    onError(err, req, res) {
        res.writeHead(500, {
            'Content-Type': 'text/plain'
        });
        res.end('Something went wrong. And we are reporting a custom error message.' + err);
    },
    onProxyRes(proxyRes, req, res) {
        //proxyRes.headers['x-added'] = 'foobar';     // add new header to response
        //delete proxyRes.headers['x-removed'];       // remove header from response
    },
    onProxyReq(proxyReq, req, res) {
        if ( req.method == "POST" && req.body ) {
            proxyReq.write( encodeURIComponent( JSON.stringify(   req.body ) ) );
            proxyReq.end();
        }
    }
};

// Proxy configuration
var proxy = require( 'http-proxy-middleware' )( proxy_filter, proxy_options );

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Node.js Express Proxy Test' });
});

router.all('/report/*', function( req, res, next ) {

    //req.body.jdbc_sas = 'jdbc:postgresql://pg_dev:5432/sasdb';
    //req.body.jdbc_agency = 'jdbc:postgresql://pg_dev:5432/agency0329';
    //console.log('proxy body:',req.body);

    proxy( req, res, next );
} );

module.exports = router;

Any suggestions are greatly appreciated.

Respectfully,

Warren.

flackenstein
  • 91
  • 1
  • 6

1 Answers1

3

Ok Here's the final solution.

The following example allows you to inject POST parameters prior to forwarding to the proxy target. You don't have scrub any parameters from the proxy target response - as far as I can tell - because it maintains a copy of the original POST request.

On a side note this also allows the http-proxy-middleware to work with body-parser.

Example Node Express Route File:

'use strict';

var express = require('express');
var router = express.Router();

var proxy_filter = function (path, req) {
    return path.match('^/docs') && ( req.method === 'GET' || req.method === 'POST' );
};

var proxy_options = {
    target: 'http://localhost:8080',
    pathRewrite: {
        '^/docs' : '/java/rep/server1' // Host path & target path conversion
    },
    onError(err, req, res) {
        res.writeHead(500, {
            'Content-Type': 'text/plain'
        });
        res.end('Something went wrong. And we are reporting a custom error message.' + err);
    },
    onProxyReq(proxyReq, req, res) {
        if ( req.method == "POST" && req.body ) {
            // Add req.body logic here if needed....

           // ....

            // Remove body-parser body object from the request
            if ( req.body ) delete req.body;

            // Make any needed POST parameter changes
            let body = new Object();

            body.filename = 'reports/statistics/summary_2016.pdf';
            body.routeid = 's003b012d002';
            body.authid = 'bac02c1d-258a-4177-9da6-862580154960';

            // URI encode JSON object
            body = Object.keys( body ).map(function( key ) {
                return encodeURIComponent( key ) + '=' + encodeURIComponent( body[ key ])
            }).join('&');

            // Update header
            proxyReq.setHeader( 'content-type', 'application/x-www-form-urlencoded' );
            proxyReq.setHeader( 'content-length', body.length );

            // Write out body changes to the proxyReq stream
            proxyReq.write( body );
            proxyReq.end();
        }
    }
};

// Proxy configuration
var proxy = require( 'http-proxy-middleware' )( proxy_filter, proxy_options );

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', { title: 'Node.js Express Proxy Test' });
});

router.all('/document', proxy );

module.exports = router;
flackenstein
  • 91
  • 1
  • 6
  • Is there a way i can modify/add `req.custom = 'value'` and pass it along the proxy for all request ? . I raised a question in github also https://github.com/chimurai/http-proxy-middleware/issues/66 – tomalex Apr 19 '16 at 18:55
  • Just ad a param to the body - IE: body.custom = "value" and that will post it to the proxy. If you want to make it work for all methods you need to use route.all for the route handler and then modify the proxy filter to handle the method/verbs you want to accept. – flackenstein Apr 21 '16 at 03:31
  • based on this https://github.com/tomalex0/middleware-patterns/blob/master/index.js can you suggest the code to add/modify `req.myvar = 'newval'` – tomalex Apr 27 '16 at 06:57
  • The body-parser hint made my day! Thanks a lot. – Fabian Aug 08 '19 at 09:40