【问题标题】:How to merge multiple responses into one json如何将多个响应合并到一个json中
【发布时间】:2018-05-22 12:41:53
【问题描述】:

如何将多个响应合并到一个 json 中?谢谢!

当我运行代码时出现错误:

错误 [ERR_HTTP_HEADERS_SENT]:发送到客户端后无法设置标头

....

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});
          });}});});

....

【问题讨论】:

  • 假设您的多个响应是 json 格式,您可以在重复函数中使用 jQuery $.merge()。

标签: javascript node.js express cheerio


【解决方案1】:

看起来传入的请求正在触发多个外部请求,这些请求被解析为一些最终要组合的统计信息,然后包含在对原始传入请求的响应中。如果这是准确的,那么这是处理多个异步请求的问题。

如何解决这个问题需要我们看看当前正在发生什么。由于外部请求都是由forEach 循环有效地并行触发的异步调用,因此首先响应的请求将触发对原始传入请求的响应。不幸的是,其余的外部请求也会在它们自己收到响应后尝试响应原始传入请求。因此,Express 关于尝试多次响应的错误。

实际上代码当前正在执行此操作(假设 x > y):

incoming req --> external req #1 (t0) --> response (t0+x) --> res.send ❌
             --> external req #2 (t0) --> response (t0+y) --> res.send ✅

注意:外部请求处于竞争状态,因此无论哪个先收到响应,都会先响应原始传入请求。

要解决这个问题,需要有一种方法来管理异步外部请求,然后合并它们的输出。

解决方案的第一部分,管理异步请求,可以通过使用 Promise 来处理。由于request 已经在代码中使用,因此可以简单地切换到使用promise 版本:request-promise注意:我们还可以利用 request-promise 中的 transform 函数来简化通过 cheerio 解析的正文。

下一部分是合并来自外部请求的解析响应。

目前,上述代码正在并行触发一堆请求。假设这不是问题,我们可以使用带有“地图”的Promise.all,而不是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 的语法糖来帮助管理 Promise。我会把它留给好奇的人练习。 ?

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 2015-04-28
    • 2018-04-09
    相关资源
    最近更新 更多