使用Node.js代理中间件将请求正文修改为JSON

时间:2018-09-25 16:30:27

标签: node.js node-http-proxy

我正在使用node-http-proxy作为中间件。处理GET请求时可以。对于具有JSON正文的POST请求,我无法发送application/json标题和json编码的正文。

这是我的中间件。我已经按照建议添加了reastream选项,但这似乎无法解决问题:

                //restream parsed body before proxying
                proxy.on('proxyReq', function (proxyReq, req, res, options) {
                    if (!req.body || !Object.keys(req.body).length) {
                        return;
                    }
                    var contentType = proxyReq.getHeader('Content-Type');
                    var bodyData;

                    if (contentType === 'application/json') {
                        bodyData = JSON.stringify(req.body);
                    }

                    if (contentType === 'application/x-www-form-urlencoded') {
                        bodyData = queryString.stringify(req.body);
                    }

                    if (bodyData) {
                        console.log("------", bodyData);
                        proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
                        proxyReq.write(bodyData);
                    }
                });
                proxy.on('proxyRes', function (proxyRes, req, res) {
                    modifyResponse(res, proxyRes, function (response) {
                        if (!MXMUtil.empty(response) && !MXMUtil.empty(response.message) && !MXMUtil.empty(response.message.body)) { // valid response
                            if (!MXMUtil.empty(response.message.body.error)) { // error response
                                var message = self.processor.createErrorMessage(500, '', response.message.body.error);
                                response = message;
                            } else { // valid response
                                var message = self.processor.prepareResponse(req_start, response.message.body);
                                response = message;
                            }
                        }
                        return response; // return value can be a promise
                    });
                });
                proxy.on('error', function (error, req, res) {
                    var errorMessage = self.processor.createErrorMessage(500, '', error.message);
                    res.send(errorMessage);
                    res.end();
                });
                proxy.web(req, res, {
                    //  url string to be parsed with the url module
                    target: target_uri,
                    //  true/false, Default: false - changes the origin of the host header to the target URL
                    changeOrigin: true,
                    //  true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request 
                    ignorePath: true
                });

在后端,我收到此错误:

Malformed HTTP message from 172.17.0.1: Malformed HTTP headers: '\r\n0\r\n\r\n'

第二个请求也将失败,并在中间件上出现Can't set headers after they are sent.错误:

[Tue Sep 25 2018 18:16:29 GMT+0200 (CEST)] trapped error code: message:Can't set headers after they are sent. stack:Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:491:11)
    at ClientRequest.setHeader (_http_outgoing.js:498:3)
    at ProxyServer.<anonymous> (/webservice/lib/api.js:616:34)
    at ProxyServer.emit (/webservice/node_modules/eventemitter3/index.js:210:27)
    at ClientRequest.<anonymous> (/webservice/node_modules/http-proxy/lib/http-proxy/passes/web-incoming.js:132:27)
    at emitOne (events.js:121:20)
    at ClientRequest.emit (events.js:211:7)
    at tickOnSocket (_http_client.js:652:7)
    at onSocketNT (_http_client.js:668:5)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickDomainCallback (internal/process/next_tick.js:218:9):

在中间件初始化之前,我正在使用主体解析器:

        // express app
        this.app = express();
        // development || production
        this.app.set('env', env);
        // custom logging: only error codes
        this.app.use(morgan('combined', {
            skip: function (req, res) {
                return res.statusCode < 400;
            }
        }));
        // LP: handle Error: request entity too large
        this.app.use(bodyParser.json({limit: '50mb'}));
        this.app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
        this.app.use(cookieParser());
        this.app.use(compression()); // gzip compression

注意。 这可能是一个错误,并且我已经打开了一个问题here,但是应该有替代方法。另一个关联的问题是here

通过curl -d {...}tornado后端提出的请求将正常工作。

[更新]

我已解决Can't set headers after they are sent.问题,在写入数据后关闭了请求:

proxyReq.write(bodyData);
proxyReq.end();

我已经尝试过将建议bodyParser放在代理使用之后的建议解决方案,但是我无法在体系结构中执行此操作,这意味着在我的情况下,顺序如下:

        httpProxy = require('http-proxy'),
        proxy = httpProxy.createProxyServer({});
        // custom logging: only error codes
            this.app.use(morgan('combined', {
                skip: function (req, res) {
                    return res.statusCode < 400;
                }
            }));
            // LP: handle Error: request entity too large
            this.app.use(bodyParser.json({ limit: '50mb' }));
            this.app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
            this.app.use(cookieParser());
            this.app.use(compression()); // gzip compression
            //...api routes...
            this.app.post(self._options.baseUrl.uri, function (req, res) {
            var req_start = new Date().getTime();
            var target_uri = self._options.proxy.uri;

            //restream parsed body before proxying
            proxy.on('proxyReq', function (proxyReq, req, res, options) {
                if (!req.body || !Object.keys(req.body).length) {
                    return;
                }
                var bodyData = JSON.stringify(req.body);
                proxyReq.setHeader('Content-Type', 'application/json');
                proxyReq.write(bodyData);
                proxyReq.end();
            });
            proxy.on('proxyRes', function (proxyRes, req, res) {
                modifyResponse(res, proxyRes, function (response) {
                    console.log("--response--->", response)
                    if (!MXMUtil.empty(response) && !MXMUtil.empty(response.message) && !MXMUtil.empty(response.message.body)) { // valid response
                        if (!MXMUtil.empty(response.message.body.error)) { // error response
                            var message = self.processor.createErrorMessage(500, '', response.message.body.error);
                            response = message;
                        } else { // valid response
                            var message = self.processor.prepareResponse(req_start, response.message.body);
                            response = message;
                        }
                    }
                    return response; // return value can be a promise
                });
            });
            proxy.on('error', function (error, req, res) {
                var errorMessage = self.processor.createErrorMessage(500, '', error.message);
                res.send(errorMessage);
                res.end();
            });
            proxy.web(req, res, {
                //  url string to be parsed with the url module
                target: target_uri,
                //  true/false, Default: false - changes the origin of the host header to the target URL
                changeOrigin: true,
                //  true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request 
                ignorePath: true
            });
        });

正如下面的评论中所注意到的,与上述代码一样,代理请求被发送了两次,因此我看到两次登录proxyReqproxyRes事件。

0 个答案:

没有答案