我如何使用" express-http-proxy"在调用bodyParser.json()之后?

时间:2015-02-06 17:42:41

标签: node.js express proxy meanjs

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

我使用" express-http-proxy"设置了/proxy路由。将所有子路由发送到其各自的后端系统端点。但是,我需要在我的管理应用程序中对每个请求进行身份验证,然后在" express-http-proxy"之前使用目标backendSystem凭据进行修饰。可以继续这是我/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凭据是根据运行我的管理员应用程序的环境存储的。但是,将来后端系统凭据将由用户指定,此/proxy路由将与当前不同所示。

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

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

有没有人有一个干净的方式,我可以为我的/proxy路由设置路由例外,以便bodyParser.json不会被调用它?

5 个答案:

答案 0 :(得分:3)

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

如果您正在阅读纯节点的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)上找到的解决方案

答案 1 :(得分:1)

我通过使用第三方查询字符串将数据转换为查询字符串来实现此目的,如下所示:

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

尝试过JSON.stringify但不能正常工作,需要以下格式的数据 array_field = val1&array_field = val2&array_field = val3 ......

答案 2 :(得分:0)

我能够通过添加一个正则表达式来解决我的问题,该正则表达式将/proxy路由排除在bodyParser.json内添加express.js的位置。我发现了answer

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

答案 3 :(得分:0)

要修改请求正文,请使用最新的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);
});

答案 4 :(得分:-1)

您可以使用proxyReq.bodyContent中的JSON-ed数据填充decorateRequest方法中的originalReq.body,以便正确发布消息:

app.use('/proxy', users.requiresLogin, expressHttpProxy(config.backendSystem.host, {
  ...
  ...
  decorateRequest: function (proxyReq, originalReq) {
    ...
    ...

    if (originalReq.body) {
      proxyReq.bodyContent = JSON.stringify(originalReq.body);
    }
    return proxyReq;
  }
  ...
  ...
}));