如何将多个回复合并为一个 json
How to merge multiple responses into one json
如何将多个回复合并为一个json?谢谢!
当我 运行 代码时出现错误:
错误[ERR_HTTP_HEADERS_SENT]:发送给客户端后无法设置headers
.....
var trackArrayReg = [
/^[A-Z]{2}\d{14}NPI$|^460\d{9}$|^959\d{9}$/i,
/^LP0\d{13}$|^[A-Z]{2}\d{14}NPI$/i
];
router.get('/:trackId', function(req, res) {
var trackId = req.params.trackId;
trackArrayReg.forEach(function(item, index, urlsArray) {
if (trackArrayReg[index].exec(trackId)) {
track = index;
request({
method: config[track].method,
url: config[track].url + trackId,
timeout: config[track].timeout,
maxAttempts: 3,
retryDelay: 500
}, function(err, response, body, callback) {
if (err) return console.error(err);
$ = cheerio.load(body);
stat = [];
$(config[track].response.rowSelector).map(function(i, links) {
var date = $(links).find(config[track].response.columnSelector).eq(config[track].response.dateColumnIndex).text(),
status = $(links).find(config[track].response.columnSelector).eq(config[track].response.stateColumnIndex).text(),
location = $(links).find(config[track].response.columnSelector).eq(config[track].response.locationColumnIndex).text();
stat.push({
location: location,
date: date,
status: status,
carrier: track
});
});
var states = JSON.parse(JSON.stringify(stat));
res.send({states});
});}});});
.....
看起来传入请求正在触发多个外部请求,这些请求被解析为一些最终要组合的统计信息,然后包含在对原始传入请求的响应中。如果这是准确的,那么这是处理多个异步请求的问题。
如何解决这个问题需要我们看看目前正在发生的事情。由于外部请求都是由 forEach
循环有效并行触发的异步调用,因此无论哪个请求先响应,都会触发对原始传入请求的响应。不幸的是,一旦它们自己收到响应,其余的外部请求也会尝试响应原始传入请求。因此 Express 关于尝试多次响应的错误。
有效代码当前正在执行此操作(假设 x > y
):
incoming req --> external req #1 (t0) --> response (t0+x) --> res.send ❌
--> external req #2 (t0) --> response (t0+y) --> res.send ✅
注意:外部请求处于竞争状态,因此首先收到响应的人将首先响应原始传入请求。
要解决这个问题,需要有一种方法来管理异步外部请求,然后合并它们的输出。
解决解决方案的第一部分,即管理异步请求,可以使用 promises 来处理。由于 request
已在代码中使用,因此只需简单地切换到使用 promise 版本:request-promise
。 注意:我们还可以利用 request-promise
中的 transform
函数来简化通过 cheerio
.
的正文解析
下一部分是合并来自外部请求的解析响应。
目前,上述代码正在并行触发一堆请求。假设这不是问题,我们可以使用 Promise.all
和 'map',而不是 forEach
,以等待所有请求响应。
注意:鉴于每个请求似乎都创建了一个值数组,因此总体结果将是这些值数组的数组。
所以在我们的流程图中我们将有:
inc req --> p.all(map(ext req #1 (t0) --> res (t0+2n) -->)) --> res.send ✅
(ext req #2 (t0) --> res (t0+n) -->)
将它们放在一起(以及一些其他语法编辑):
注意:这是未经测试的代码。
const requestPromise = require('request-promise-native');
const trackArrayReg = [
/^[A-Z]{2}\d{14}NPI$|^460\d{9}$|^959\d{9}$/i,
/^LP0\d{13}$|^[A-Z]{2}\d{14}NPI$/i
];
router.get('/:trackId', ({params: {trackId}}, res) => {
Promise.all(trackArrayReg.map((regexp, track) => {
if (regexp.test(trackId)) {
return requestPromise({
method: config[track].method,
url: config[track].url + trackId,
timeout: config[track].timeout,
maxAttempts: 3,
retryDelay: 500,
transform(body) {
return cheerio.load(body);
}
}).then(($) => {
const rows = $(config[track].response.rowSelector);
return rows.map((links) => {
const columns = $(links).find(config[track].response.columnSelector);
const date = columns.eq(config[track].response.dateColumnIndex).text();
const status = columns.eq(config[track].response.stateColumnIndex).text();
const location = columns.eq(config[track].response.locationColumnIndex).text();
return {
location,
date,
status,
carrier: track
};
});
}).catch((err) => {
console.error(err)
});
}
})).then((stats) => {
// Combine or modify the stats array as desired
res.json(stats);
});
});
要进一步练习重构,您还可以使用 async/await 的语法糖来帮助管理承诺。我会把它作为好奇的练习。
希望对您有所帮助!
如何将多个回复合并为一个json?谢谢!
当我 运行 代码时出现错误:
错误[ERR_HTTP_HEADERS_SENT]:发送给客户端后无法设置headers
.....
var trackArrayReg = [
/^[A-Z]{2}\d{14}NPI$|^460\d{9}$|^959\d{9}$/i,
/^LP0\d{13}$|^[A-Z]{2}\d{14}NPI$/i
];
router.get('/:trackId', function(req, res) {
var trackId = req.params.trackId;
trackArrayReg.forEach(function(item, index, urlsArray) {
if (trackArrayReg[index].exec(trackId)) {
track = index;
request({
method: config[track].method,
url: config[track].url + trackId,
timeout: config[track].timeout,
maxAttempts: 3,
retryDelay: 500
}, function(err, response, body, callback) {
if (err) return console.error(err);
$ = cheerio.load(body);
stat = [];
$(config[track].response.rowSelector).map(function(i, links) {
var date = $(links).find(config[track].response.columnSelector).eq(config[track].response.dateColumnIndex).text(),
status = $(links).find(config[track].response.columnSelector).eq(config[track].response.stateColumnIndex).text(),
location = $(links).find(config[track].response.columnSelector).eq(config[track].response.locationColumnIndex).text();
stat.push({
location: location,
date: date,
status: status,
carrier: track
});
});
var states = JSON.parse(JSON.stringify(stat));
res.send({states});
});}});});
.....
看起来传入请求正在触发多个外部请求,这些请求被解析为一些最终要组合的统计信息,然后包含在对原始传入请求的响应中。如果这是准确的,那么这是处理多个异步请求的问题。
如何解决这个问题需要我们看看目前正在发生的事情。由于外部请求都是由 forEach
循环有效并行触发的异步调用,因此无论哪个请求先响应,都会触发对原始传入请求的响应。不幸的是,一旦它们自己收到响应,其余的外部请求也会尝试响应原始传入请求。因此 Express 关于尝试多次响应的错误。
有效代码当前正在执行此操作(假设 x > y
):
incoming req --> external req #1 (t0) --> response (t0+x) --> res.send ❌
--> external req #2 (t0) --> response (t0+y) --> res.send ✅
注意:外部请求处于竞争状态,因此首先收到响应的人将首先响应原始传入请求。
要解决这个问题,需要有一种方法来管理异步外部请求,然后合并它们的输出。
解决解决方案的第一部分,即管理异步请求,可以使用 promises 来处理。由于 request
已在代码中使用,因此只需简单地切换到使用 promise 版本:request-promise
。 注意:我们还可以利用 request-promise
中的 transform
函数来简化通过 cheerio
.
下一部分是合并来自外部请求的解析响应。
目前,上述代码正在并行触发一堆请求。假设这不是问题,我们可以使用 Promise.all
和 'map',而不是 forEach
,以等待所有请求响应。
注意:鉴于每个请求似乎都创建了一个值数组,因此总体结果将是这些值数组的数组。
所以在我们的流程图中我们将有:
inc req --> p.all(map(ext req #1 (t0) --> res (t0+2n) -->)) --> res.send ✅
(ext req #2 (t0) --> res (t0+n) -->)
将它们放在一起(以及一些其他语法编辑): 注意:这是未经测试的代码。
const requestPromise = require('request-promise-native');
const trackArrayReg = [
/^[A-Z]{2}\d{14}NPI$|^460\d{9}$|^959\d{9}$/i,
/^LP0\d{13}$|^[A-Z]{2}\d{14}NPI$/i
];
router.get('/:trackId', ({params: {trackId}}, res) => {
Promise.all(trackArrayReg.map((regexp, track) => {
if (regexp.test(trackId)) {
return requestPromise({
method: config[track].method,
url: config[track].url + trackId,
timeout: config[track].timeout,
maxAttempts: 3,
retryDelay: 500,
transform(body) {
return cheerio.load(body);
}
}).then(($) => {
const rows = $(config[track].response.rowSelector);
return rows.map((links) => {
const columns = $(links).find(config[track].response.columnSelector);
const date = columns.eq(config[track].response.dateColumnIndex).text();
const status = columns.eq(config[track].response.stateColumnIndex).text();
const location = columns.eq(config[track].response.locationColumnIndex).text();
return {
location,
date,
status,
carrier: track
};
});
}).catch((err) => {
console.error(err)
});
}
})).then((stats) => {
// Combine or modify the stats array as desired
res.json(stats);
});
});
要进一步练习重构,您还可以使用 async/await 的语法糖来帮助管理承诺。我会把它作为好奇的练习。
希望对您有所帮助!