如何根据动态创建的请求数组执行多个axios get请求

Posted

技术标签:

【中文标题】如何根据动态创建的请求数组执行多个axios get请求【英文标题】:How to execute multiple axios get requests based of an array of requests created dynamically 【发布时间】:2019-10-18 10:27:03 【问题描述】:

我正在尝试学习 Angular/node & express。我目前正在尝试为我支持的那个写一个端点

    需要使用 axios 向外部 API 运行获取请求,该 API 将返回 ID(数字)列表 对于提供的每个 ID,运行一个请求,根据该 ID 获取详细信息。

但我的问题是关于 2 号。我有一个 ID 列表作为输入,我想根据每个 ID 运行对外部 API(使用 axios)的请求。请注意 - 基于 ID 对外部 API 的请求会返回一个包含该 ID 详细信息的对象,因此我的 API 端点的总体目标是返回一个对象数组,其中每个对象都包含ID。

有几个和我类似的问题...

    Pushing responses of axios request into array(这个和我的问题很相似) Axios random number of requests

但是,他们使用的是 React.js,我很难将他们的解决方案调整为 node/express。

我正在尝试根据第一个问题的顶部提供的代码 sn-p 来模拟我的方法。但是,我的解决方案是返回一个空对象作为响应。

我的问题:我可以做些什么不同的事情来向动态创建每个请求的外部 API 发出多个 axios GET 请求

app.route('/test').get((req, res) => 
    axios
        .get('https://www.thecocktaildb.com/api/json/v1/1/filter.php?i=vodka')//This will not be hardcoded, but grabbed as a parameter from the endpoint
        .then(function(response) 
            //Purpose of this initial .then() clause is to make a call to the cocktaildb API to get the IDs of all the cocktails with a given ingredient eg: vodka.

            var data = response.data;//response.data contains the JSON object containing the contents received by the cocktaildb API request.
            var cocktailIds = [];

            //collect all cocktail ids so we can later make more requests to obtain the details associated with that ID.
            data.drinks.forEach(drink => 
                cocktailIds.push(drink['idDrink']);
            );

            //this is passed on to the next then clause. It is a list of cocktail ids.
            return cocktailIds;
        )
        .then((drinks) => 
            //the promises variable contains a list of all the requests we will have to make in order to get the details of all cocktail ids. I have tested that they are valid requests.
            const promises = drinks.map(id => 
                //console.log(getCocktailDetailsUrl + id);
                return axios.get(getCocktailDetailsUrl + id)
                .then((data) => 
                    return data;
                )
            )
            
            //I was hoping Promise.All to execute all of the requests in the promise and response to be stored in the cocktailDetails variable
            const cocktailDetails = Promise.all(promises)
            .then(values => 
                return values;
            )
            .catch(error => 
                console.log("There was an error when sending requests for details of all cocktails");
                console.log(error);
            )

            //Sending response only formatted this way for testing purposes
            if(cocktailDetails) 
                //this block is executed, and an empty object is returned as response
                console.log("cocktails was sent as response");
                res.send(cocktailDetails);
             else 
                console.log("cocktails was not sent as response");
                res.send("cocktailDetails was not poppulated at the time of sending response");
            
        )
        .catch(function (error) 
            res.send("There was an iswsue with your request to the cocktaildb API.");
            console.log('The following is the error from the request to the cocktaildb API: ' + error);
        )
);

正如我之前提到的,我的响应包含一个空对象。我知道我必须以某种方式使用 promise.all,但我不确定如何正确实现它。

【问题讨论】:

是否已安装 bluebird 并分配给 global.Promise 或仅需要作为 const Promise = require('bluebird')? AFAIK Promise.all 在 node.js 中不可用 注意蓝鸟是什么。但是,promise.all 工作正常,我只是没有正确使用它。例如,我注意到当我将上面的代码修改为..Promise.all(promises) .then(values => console.log(values[0]); return values; ) 时,我实际上从我计划发出的请求列表中的第一个请求中得到了我想要的响应。但是,我想我会将响应数据存储在const cocktailDetails 中。我需要弄清楚如何访问 .then() 之外的响应 看我的答案为什么,但你可以使用其他人的答案以及他的答案也是正确的 【参考方案1】:

您的问题是在发送响应之前您没有等待所有承诺解决。额外的批评,您的代码可以大大简化为以下内容:

app.route('/test').get((req, res) => 
    axios.get('https://www.thecocktaildb.com/api/json/v1/1/filter.php?i=vodka')//This will not be hardcoded, but grabbed as a parameter from the endpoint
    .then(function(response) 

        const promises = response.data.drinks.map(drink =>axios.get(getCocktailDetailsUrl + drink.idDrink).then((data)=>data));

        //I was hoping Promise.All to execute all of the requests in the promise and response to be stored in the cocktailDetails variable
        return Promise.all(promises)
        .then(values => 
            res.send(values);// shouldn't you be using res.json() here?
        );//if an error is thrown for any reason here, it will be caught by your outer catch 
    )
    .catch(function (error) 
        res.send("There was an iswsue with your request to the cocktaildb API.");
        console.log('The following is the error from the request to the cocktaildb API: ' + error);
    );
);

【讨论】:

感谢您的额外批评,我知道我的解决方案并不优雅,正在寻找提示。关于等待承诺解决,我不能简单地在Promise.all 之前添加await,因为await 只能在async Function 中使用,我是否必须重新实现我的代码以便此功能以异步方式存在功能。编辑:添加更多评论,因为我不小心提前提交了 Promise 应该符合 async 函数。我看到很多人这样做。我个人还没有采用异步/等待,所以我不知道。我只是坚持古老的承诺。你试过我的代码了吗?它应该工作。另请阅读我对res.send() 行的评论。你不应该在那里使用res.json()吗? 您的解决方案有效。我真的很感谢你的帮助。是的,应该是res.json()。我只是问,因为我想我可以简单地在我的Promise.all 前面添加await,但我得到一个'await 仅在异步函数中有效'。我不需要解决问题,因为您的解决方案有效并且我将使用它,我只是为了学习目的而试图弄清楚,因为我很难掌握承诺和相关概念。 @Ryan 的承诺很简单。如果你把它们给了但忘记了它们,你将无法判断承诺是否被遵守,所以如果你在其他地方需要这些值,请务必返回承诺。如果您根据承诺的结果执行操作,那么您需要等待它解决后再执行操作。希望对您的理解有所帮助。我有时不擅长解释 这很有帮助,谢谢。我对您解决方案的这一部分有疑问const promises = response.data.drinks.map(drink =>axios.get(getCocktailDetailsUrl + drink.idDrink).then((data)=>data));。你能解释一下.then((data)=>data)在做什么的逻辑吗?【参考方案2】:

在尝试发送响应之前,您应该等待承诺。

Promise.all 之前添加await,您不需要then

const cocktailDetails = await Promise.all(promises)

【讨论】:

这是对的,但没有回答问题。您应该向程序员指出为什么他得到一个空响应(他不会在发送响应之前等待Promise.all() 解决。)

以上是关于如何根据动态创建的请求数组执行多个axios get请求的主要内容,如果未能解决你的问题,请参考以下文章

React - 多个 Axios 请求

如何在 vuejs 中使用 axios 从数组中发布多个请求?

Axios-一次发出多个请求(vue.js)

多个请求执行完再执行下一个方法(vue Promise.all用法)

如何执行两个 Axios GET 请求,映射结果然后将其推送到数组?

动态创建多个数组