我有一个用于调用服务的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的事实。
答案 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?