解析管道响应有时会得到分块数据

时间:2016-03-30 12:13:48

标签: node.js stream request pipe response

我有一个用于调用服务的nodejs代理。在响应上,请求被传送到服务URL(如果你想在返回之前解析响应,我想这是正确的方法)。问题是解析器有时会在JSON.parse(数据)上失败,因为它意外结束了输入。从我在调试问题时看到的是,正在解析的数据不完整(即使服务正确地返回它)。 我对管道和流没有太多经验,所以我不知道为什么有时会失败。

//Request setup
            r.on('response', function(resp) {
            if (resp.statusCode === 200) {
                r.pipe(responseParser(config.get('service:url'))).pipe(res);
            } else {
                r.pipe(res);
            }
        });

//Parser module
    var _ = require('lodash'),
        stream = require('stream');

    module.exports = function responseParser(url) {
        var data = '',
            parser = new stream.Transform({
                objectMode: true
            });

        parser._transform = function (chunk, encoding, done) {
            data += chunk.toString();
            done();
        };

        parser._flush = function (done) {
            if (data) {
                var obj = mapValues(JSON.parse(data));
                    this.push(JSON.stringify(obj));
            }

            done();
        };

        function mapValues(data){
            ...
        }

        return parser;
    }   

我仍然不知道为什么有时在返回所有数据块之前调用flush,但我为了避免这种情况而做的只是在它们到达时解析块,确保在块中我不要获得我需要映射的值的部分数据。如果一个块只包含目标值的部分信息,我将其删除,并将其添加到下一个块的开头。这样就可以在数据进入时对数据进行解析,因此我不必依赖只有在返回所有数据时才调用flush的事实。

2 个答案:

答案 0 :(得分:0)

我会禁用objectMode,因为在这种情况下没有必要。此外,如果输入格式错误,您还需要在try-catch中包装JSON解析:

module.exports = function responseParser(url) {
  var data = '';
  var parser = new stream.Transform();
  parser._transform = function(chunk, encoding, done) {
    data += chunk;
    done();
  };
  parser._flush = function(done) {
    var err;
    if (data) {
      try {
        var obj = mapValues(JSON.parse(data));
        this.push(JSON.stringify(obj));
        this.push(null);
      } catch (ex) {
        err = ex;
      }
    }
    done(err);
  };

  function mapValues(data){
    // ...
  }

  return parser;
};

您可能还想先检查resp.headers['content-type']是否包含application/json,然后再尝试解析它,您可能想要创建一个自定义的Transform子类并实例化它而不是创建新的_transform()每次都有_flush()个函数。

答案 1 :(得分:0)

为什么不使用知道如何解析流的流式JSON解析器,而不是自己编写?例如JSONStream

让您的生活更轻松的另一个选择是使用stream-to-promise将读取流转换为Promise,它将解析为JSON的缓冲区,然后您可以解析它。

另外,为什么你的代理解析JSON?