【问题标题】:Async/await with forEach and axios使用 forEach 和 axios 进行异步/等待
【发布时间】:2023-03-30 19:40:01
【问题描述】:

我遇到了一个问题,需要您的帮助。 我需要在一个名为 rudder 的软件中使用 API 来自动注册服务器。 为了达到我的目标,我必须使用 2 个 http 请求:

  1. (GET) 获取所有状态为pending的服务器
  2. (POST) 注册我的服务器

我的第一个请求得到了完美处理,但我不知道如何进行第二个请求。

这是我的代码 (/src/controllers/registration.js):

async function index(req, res) {
  // Check parameter
  if (!req.body.hostname) {
    return res.status(422).json({ result: 'error', message: 'Missing hostname parameter' });
  }

  try {
    const pendingNodes = await axios.get(`${config.rudderURL}/rudder/api/latest/nodes/pending?include=minimal`, { headers });
    Object.keys(pendingNodes.data.data.nodes).forEach((key) => {
      // Search in all pending machine if our node is present
      const node = pendingNodes.data.data.nodes[key];
      if (req.body.hostname === node.hostname) {
        // Registration
        const response = async axios.get(`${config.rudderURL}/rudder/api/nodes/pending/${node.id}`, { headers });
        // console.log(response);
        return res.status(200).json({ result: 'success', message: 'Host added to rudder' });
      }
    });
  } catch (err) {
    return res.status(500).json({ result: 'error', message: `${err}` });
  }

  return res.status(500).json({ result: 'error', message: 'Host not found' });
}

如您所见,我使用Object.keys(...).forEach(...) 来遍历我的第一个请求的结果。

供您参考,第一个请求的响应是这样的:

{
    "action": "listPendingNodes",
    "result": "success",
    "data": {
        "nodes": [
            {
                "id": "f05f2bde-5416-189c-919c-954acc63dce7",
                "hostname": "foo",
                "status": "pending"
            },
            {
                "id": "b7f597ef-2b46-4283-bf70-d5e8cd84ba86",
                "hostname": "bar",
                "status": "pending"
            }
        ]
    }
}

我需要遍历此输出并将每个 nodes 的主机名字符串与我的输入(来自脚本或邮递员的简单发布请求)进行比较。

如果 2 字符串相等,我的第二个请求是启动,并且必须在服务器中注册我的主机(请求在这里被简化,但你明白了)。

我的问题是我找不到使第二个请求起作用的方法。我尝试了不同的解决方案,并在一些论坛和网站上阅读到同时使用循环和异步/等待很复杂,但你对我有什么想法吗?

当我尝试我的代码时,我收到一条错误消息:

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

据我了解,forEach(...) 不等待我的第二次请求结果。所以return res.status(200).json({ result: 'success', message: 'Host added to rudder' }); 被称为然后另一个,可能是return res.status(500).json({ result: 'error', message: 'Host not found' });。我说的对吗?

我的意思是,真正的困难(或不是?)是Object.keys(...).forEach(...)。也许有一种简单的方法可以不使用此功能而是另一种?还是重构我的代码?

问候。

【问题讨论】:

  • 看起来您正在检查主机名是否相同,并且在 forEach 的每次迭代中都返回 res.status(200)。这似乎是您的错误的原因,因为一个人将其发回,然后另一个人出现并尝试再次将响应发回。此外,您似乎有 const response = async axios.get... 用于注册。那不应该是等待 axios.get...?

标签: javascript node.js async-await axios


【解决方案1】:

异步等待在 forEach 循环中不起作用。 将您的 forEach 转换为 for 循环。 像这样:

let nodes = Object.keys(pendingNodes.data.data.nodes;
for (let i = 0; i < nodes.length; i++) {
    // Perform asynchronous actions and await them, it will work
    ...
}

在此处阅读更多信息:Using async/await with a forEach loop

另外, 一个函数是异步的,您可以在其中等待多个语句。 你在axios.get 前面写了异步,它基本上返回了一个承诺。 你应该在等待。

更改以下内容

const response = async axios.get(`${config.rudderURL}/rudder/api/nodes/pending/${node.id}`, { headers });

const response = await axios.get(`${config.rudderURL}/rudder/api/nodes/pending/${node.id}`, { headers });

【讨论】:

    【解决方案2】:

    你得到的错误

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

    这是因为你多次调用res.status(200)(你把它放在 forEach 循环中)。此响应只能执行一次。

    我一直在研究解决方案并想出使用reducemapPromise.all

    async function index(req, res) {
      // Check parameter
      ...
    
      try {
        const pendingNodes = await axios.get(`${config.rudderURL}/rudder/api/latest/nodes/pending?include=minimal`, { headers });
    
        // we get node ids in array with hostname is matched with req.body.hostname
        const nodeIdsToRegister = pendingNodes.data.data.nodes.reduce((result, node) => {
          return req.body.hostname === node.hostname ? [...result, node.id] : result;
        }, [])
    
        // use `Promise.all` to register all node Ids we got previously
        const registers = await Promise.all(nodeIdsToRegister.map(nodeId => axios.get(`${config.rudderURL}/rudder/api/nodes/pending/${node.id}`, { headers })));
    
        res.status(200).json({ result: 'success', message: 'Host added to rudder' });
    
      } catch (err) {
        return res.status(500).json({ result: 'error', message: `${err}` });
      }
    
      return res.status(500).json({ result: 'error', message: 'Host not found' });
    }
    

    【讨论】:

    • 谢谢!简单,无循环,兼容 babel 默认配置。
    猜你喜欢
    • 2015-07-27
    • 2018-11-25
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 2019-02-10
    • 2019-07-29
    相关资源
    最近更新 更多