我遇到了问题,需要您的帮助。 我需要在名为rudder的软件中使用和API来自动注册服务器。 为了达到我的目标,我必须使用2个http请求:
我的第一个请求可以完美处理,但是我不知道如何提出第二个请求。
这是我的代码(/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(...)
。也许有一种简单的方法可以不使用此功能,而不必使用另一个功能?还是重构我的代码?
致谢。
答案 0 :(得分:3)
异步等待在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
的前面编写了一个异步操作,它基本上返回了一个Promise。
您应该在等待。
更改以下内容
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 });
答案 1 :(得分:2)
您遇到的错误
错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置
这是因为您多次调用res.status(200)
(将其放入forEach循环中)。此响应只能执行一次。
我一直在研究解决方案,并开始使用reduce
,map
和Promise.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' });
}