【问题标题】:How to access the body of a request outside in an async function?如何在异步函数中访问外部请求的主体?
【发布时间】:2023-04-04 21:06:01
【问题描述】:

所以我有一个发布路由,它是一个异步等待函数,我在其中有一个 reuest,它从 api 中提取一些数据,我想将该主体的内容保存在请求函数外部的变量中

我尝试过使用 Promise,但我对此并不十分熟悉。

//@route POST api/portfolio/stock
//@desc Create or update a user's stock portfolio
//@access private
router.post(
  "/stock",
  auth,
  [
    check("symbol", "symbol is require or incorrect.")
      .not()
      .isEmpty(),
    check("qty", "Quantity of the stock purchased is required")
      .not()
      .isEmpty()
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty) {
      return res.status(400).json({ errors: errors.array() });
    }

    const { stock, qty } = req.body;

    const newPortfolio = {};
    newPortfolio.user = req.user.id;
    newPortfolio.stocks = [];
    if(stock) newPortfolio.stocks.stock = stock;
    if(qty) newPortfolio.stocks.qty = qty;

    request(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${stock}&apikey=${config.get(
            "API_KEY")}`, (error, response, body) => {
            if (error) console.error(error);

            if (response.statusCode !== 200) {
                        res.status(404).json({msg: 'No stock found'});
                      }

            let content = JSON.parse(body);
            let quote = content['Global Quote'];
        });

    newPortfolio.stocks.stockInfo = quote;

    try {

        let portfolio = await Portfolio.findOne({ user: user.req.id });

        //update if exists
        if(portfolio) {

            portfolio = await Portfolio.findOneAndUpdate(
                { user: user.req.id },
                { $push: { stocks: newPortfolio.stocks }}
            );

            return res.json(portfolio);

        }

        //create if not found
        portfolio = new Portfolio(newPortfolio);
        await portfolio.save();
        res.json(portfolio);

    } catch (err) {
      console.error(err.message);
      res.status(500).send("Server Error");
    }
  }
);

我想使用该请求的正文保存 myPortfolio.stocks.stockInfo。

【问题讨论】:

  • 你没有。您在request() 回调中继续您的函数的其余部分,因为这是body 数据可用的唯一地方。这是 Javascript 中异步编程的基础知识。你也可以使用 Promise 和 async/await,但这需要你学习如何正确使用 Promise 和 async/await 才能正确使用它。提示,request-promise 库是 request 库的承诺返回版本。

标签: javascript node.js api asynchronous request


【解决方案1】:

如何在异步函数中访问外部请求的正文?

你没有。异步结果仅在异步上下文中可用。对于通过回调返回结果的异步函数,这意味着您在回调内部使用/使用结果。任何需要访问这些结果的代码都在回调中。在传统的异步 Javascript 编程中,您只需在回调中继续您的函数代码。

幸运的是,promise 和 asyncawait 的发明可以使编码更简单一些。对于返回 Promise(而不是回调)的异步函数,您可以使用 await 来获取它们的结果,并且您可以编写看起来更像顺序模型的代码,即使它仍然是异步的。

例如,这就是你的函数的重写可能看起来像我们切换请求承诺库(与请求库相同,但返回一个承诺而不是使用回调)然后我们使用await on结果:

const rp = require('request-promise');

router.post(
    "/stock",
    auth,
    [
        check("symbol", "symbol is require or incorrect.")
        .not()
        .isEmpty(),
        check("qty", "Quantity of the stock purchased is required")
        .not()
        .isEmpty()
    ],
    async (req, res) => {
        const errors = validationResult(req);
        if (!errors.isEmpty) {
            return res.status(400).json({
                errors: errors.array()
            });
        }

        const {
            stock,
            qty
        } = req.body;

        const newPortfolio = {};
        newPortfolio.user = req.user.id;
        newPortfolio.stocks = [];
        if (stock) newPortfolio.stocks.stock = stock;
        if (qty) newPortfolio.stocks.qty = qty;

        try {
            let body = await rp(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${stock}&apikey=${config.get("API_KEY")}`);
            let content = JSON.parse(body);
            newPortfolio.stocks.stockInfo = content['Global Quote'];
        } catch (e) {
            console.error(e);
            res.status(404).json({
                msg: 'No stock found'
            });
            return;
        }


        try {

            let portfolio = await Portfolio.findOne({
                user: user.req.id
            });

            //update if exists
            if (portfolio) {

                portfolio = await Portfolio.findOneAndUpdate({
                    user: user.req.id
                }, {
                    $push: {
                        stocks: newPortfolio.stocks
                    }
                });

                return res.json(portfolio);

            }

            //create if not found
            portfolio = new Portfolio(newPortfolio);
            await portfolio.save();
            res.json(portfolio);

        } catch (err) {
            console.error(err.message);
            res.status(500).send("Server Error");
        }
    }
);

注意:您将属性添加到 newPortfolio.stocks 这是一个数组是非常不寻常的。虽然这在技术上没有错,但如果您只是要向它添加属性而不是像实际数组一样使用它,您通常会将 newPortfolio.stocks 声明为一个对象,而不是一个数组。如果您将相同的变量同时用作对象和数组,那么阅读您的代码的人通常会感到困惑。通常,您希望一个变量(或属性)表现得像一个或另一个,而不是两者。

【讨论】:

  • 谢谢你,这对我帮助很大,在你的帮助下,我能够将商店数据提取到 newPortfolio.stocks 并将其更改为一个对象,但是当我在邮递员中发布此请求时说服务器错误并说用户未定义,你有解决办法吗?
  • @SakshamSaraswat - 我不明白你的新问题是什么。也许您应该在新问题中准确描述问题所在?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-18
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多