【问题标题】:How can I use "express-http-proxy" after bodyParser.json() has been called?调用 bodyParser.json() 后如何使用“express-http-proxy”?
【发布时间】:2015-04-06 22:36:17
【问题描述】:

我正在构建一个跨系统管理应用程序,它将用作多个后端系统的管理工具。该应用建立在 Mean.js 之上。

我已经使用“express-http-proxy”设置了一个/proxy 路由,以将所有子路由发送到它们各自的后端系统端点。但是,我需要在我的管理应用程序中对每个请求进行身份验证,然后使用目标 backendSystem 凭据进行装饰,然后“express-http-proxy”才能继续。这是我的/proxy 路由示例...

app.use('/proxy', users.requiresLogin, expressHttpProxy(config.backendSystem.host, {
    forwardPath: function (req) {
        return '/1.0' + require('url').parse(req.url).path;
    },
    decorateRequest: function (req) {
        req.headers['content-type'] = 'application/json';
        req.headers['backend-system-id'] = config.backendSystem.id;
        req.headers['backend-system-key'] = config.backendSystem.key;
        return req;
    }
}));

注意:
目前 backendSystem 凭据是根据运行我的管理应用程序的环境存储的。但是,将来 backendSystem 凭据将由用户指定,并且此 /proxy 路由将与当前显示的不同。

问题:
需要请求正文中的数据的代理路由不起作用。
例如POST /comments {"user": user_id, "text": "rabble rabble rabble"}

我发现了什么:
bodyParser.json() 和“express-https-proxy”不太好用。我已经通过从express.js 中删除bodyParser.json() 来确认这一点。 但是,这不是一个完整的解决方案,因为我几乎所有其他路线都需要bodyParser.json,例如/auth/signin.

有没有人有一个干净的方法可以让我的 /proxy 路由例外,这样bodyParser.json 就不会被调用?

【问题讨论】:

    标签: node.js express proxy meanjs


    【解决方案1】:

    要修改请求正文,请使用最新的 express-http-proxy v1.6.2:

    const express = require('express');
    const proxy = require('express-http-proxy');
    const bodyParser = require('body-parser');
    
    const conf = {
        proxyHost:      'some.example.net:9200',
        proxyOptions: {
            proxyReqBodyDecorator:  modifyRequestBody,
            preserveHostHdr:        true,
            parseReqBody:           true
        },
        port:   8073
    };
    
    var app = express();
    app.use('/proxy', proxy(conf.proxyHost, conf.proxyOptions));
    
    function modifyRequestBody(body, srcReq) {
        if(srcReq.method.match(/^(GET|POST)$/i)) {
            try {
                // convert buffer to string, then to object
                var str = Buffer.from(body).toString('utf-8');
                var reqBody = JSON.parse(str);
                if(someCondition)) {
                    reqBody.addStuff = 'whatever';
                    body = reqBody; // return modified body as object
                }
            } catch(error) {
                console.log('- error: ' + JSON.stringify(error));
            }
        }
        return body; // return original buffer, or modified object
    }
    
    app.listen(conf.port, function () {
        log('app listening on port ' + conf.port);
    });
    

    【讨论】:

      【解决方案2】:

      我通过使用 3rd 方查询字符串将数据转换为查询字符串来使其工作,如下所示:

      proxyReqBodyDecorator: function(bodyContent, srcReq) {
          return (queryString.stringify(bodyContent));
      }
      

      试过JSON.stringify但不行,需要以下格式的数据 array_field=val1&array_field=val2&array_field=val3......

      【讨论】:

        【解决方案3】:

        您可以使用来自originalReq.body 的 JSON 数据填充 decorateRequest 方法内的 proxyReq.bodyContent 以正确发布:

        app.use('/proxy', users.requiresLogin, expressHttpProxy(config.backendSystem.host, {
          ...
          ...
          decorateRequest: function (proxyReq, originalReq) {
            ...
            ...
        
            if (originalReq.body) {
              proxyReq.bodyContent = JSON.stringify(originalReq.body);
            }
            return proxyReq;
          }
          ...
          ...
        }));
        

        【讨论】:

        • 它不起作用。请求中没有这样的变量。
        【解决方案4】:

        据我了解,问题的根源是这样的:

        如果你是通过纯节点读取 POST 请求,你应该使用这样的代码

        if (req.method == 'POST') {
            console.log("POST");
            var body = '';
            req.on('data', function (data) {
                body += data;
                console.log("Partial body: " + body);
            });
            req.on('end', function () {
                console.log("Body: " + body);
            });
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end('post received');
        }
        

        换句话说,您需要使用 req.on('data') & req.on('end') 事件。 但问题是,您只能使用此代码一次。调用 'end' 后,请求被消费。

        那么你使用 bodyParser ,它消费请求,代理与它无关。

        实际上,在我看来,代理等待“数据”事件出现,但它会更新发生,所以代码会暂停。

        解决办法:

        您需要“重新启用”这些事件。我使用了这段代码,它对我有用。

        var express = require('express');
        var bodyParser = require('body-parser');
        var http = require('http');
        
        //call for proxy package
        var devRest = require('dev-rest-proxy');
        
        //init express (as default)
        var users = require('./routes/users');
        var app = express();
        app.use(bodyParser.json());
        
        //set the proxy listening port
        app.set('port', 8080);
        
        //process the POST request
        app.post('/users/*', function(req, res) {
        
            //just print the body. do some logic with it
            console.log("req.body: ",req.body);
        
            //remove listeners set by bodyParser
            req.removeAllListeners('data');
            req.removeAllListeners('end');
        
            //add new listeners for the proxy to use
            process.nextTick(function () {
            if(req.body) {
               req.emit('data', JSON.stringify(req.body));
            }
            req.emit('end');
            });
        
            //forward the request to another server
            devRest.proxy(req,res, 'localhost', 3000);    
        
        });
        
        //start the proxy server
        http.createServer(app).listen(app.get('port'), function(){
            console.log("Express server listening on port " + app.get('port'));
        });
        
        module.exports = app;
        

        schumacher-m帖子(nodejitsu的github)上找到的解决方案

        【讨论】:

        • 我尝试了这个修复,但它不起作用。有什么建议吗?
        • 我在使用它时只得到身体的一部分。所以适用于较小的有效载荷
        • 感谢上帝堆栈溢出。这对我有用!
        【解决方案5】:

        我能够通过添加一个正则表达式来解决我的问题,该正则表达式排除了我的 /proxy 路由到 bodyParser.jsonexpress.js 中添加的位置。我从这个answer 发现的

        虽然这种方法不能很好地扩展,但它解决了我的直接问题。

        【讨论】:

        • 您能解释一下您的解决方案吗?我也面临同样的问题
        猜你喜欢
        • 1970-01-01
        • 2016-05-26
        • 2015-08-06
        • 1970-01-01
        • 2017-03-05
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 2017-06-14
        相关资源
        最近更新 更多