【问题标题】:Node. get data from database and and make post request with results [duplicate]节点。从数据库中获取数据并使用结果发出发布请求[重复]
【发布时间】:2016-11-30 18:47:55
【问题描述】:

我有一个数据库中的用户列表。在注册 db 时,他们最初获得了 access_token,但随着它过期,我需要通过 refresh_token 创建一个新的 access_token,它也已保存在 db 中针对用户。

我需要向端点发出 POST 请求以获取新的访问令牌。

我正在尝试遍历数据库中的每一行并以这种方式获取新的 access_token。当有一个用户时,它工作得很好,但是当users 数组中有多个用户时,每个user 都是相同的,即数据库表中的最后一个用户。我猜该请求尚未完成,它正在尝试发送新请求或类似的东西。

有谁知道如何解决这个问题?

app.get('/get-users', function (req, res) {
    connection.query('SELECT * from users', function(err, rows, fields) {
        if(err) console.log(err);

        for(var i = 0; i < rows.length; i++) {
            name = rows[i].name;
            userId = rows[i].userId;
            console.log(userId);// this gives the correct userid
            var authOptions = {
                url: url,
                headers: {
                    'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
                },
                form: {
                    grant_type: 'refresh_token',
                    refresh_token: refresh_token
                },
                json: true
            };

            request.post(authOptions, function(error, response, body) {
                if (!error && response.statusCode === 200) {
                    var access_token = body.access_token;
                    users.push({name: name, userId: userId, accessToken: access_token});
                    console.log(userId)//gives last entry in db
                }
            });
        setTimeout(function () {
           console.log(users)
         }, 3000)
        }
    });
   res.send('getting here');
})

【问题讨论】:

  • 你在 30 分钟前问过这个问题,它被关闭了:stackoverflow.com/questions/40884069/…
  • @xShirase 我知道,对不起!我想让它首先与一个用户一起工作,因为我不是 100% 确定这是否是问题,但现在我知道它是。正如我所说,问题不在于向浏览器发送响应,而是将正确的数据推送到users 数组中。也感谢您的帮助,我真的很感激
  • 我仍然不确定您要做什么。您每次都在一次刷新所有用户令牌?
  • 无论如何,摆脱for循环,创建一个处理POST请求的函数,当函数完成时res.send
  • @xShirase 我有一个refresh_tokens 列表,需要更改为access_tokens。这实际上是有效的。我认为问题一定是你对函数所说的,但我不是 100% 确定函数的外观以及它将在 js 文件中调用/转到的位置

标签: javascript node.js spotify


【解决方案1】:

你的问题是这样的:

    for(var i = 0; i < rows.length; i++) {
        name = rows[i].name;
        userId = rows[i].userId;
        // ...
        request.post(authOptions, function(error, response, body) {
          // you're using name and userId here
        });
        // and also you use users here:
        console.log(users)
    }

现在,问题是在所有循环迭代完成之前不会调用任何回调(即使是第一次迭代)。

首先,console.log(users) 将始终获得 users 的值,无论它任何users.push() 发生之前是什么。

此外,对于每个回调nameuserId 的值将是相同的 - 无论在您的 for 循环的最后一次迭代之后是什么。

您的nameuserId 似乎是全局变量,或者它们是在某个外部范围内定义的。您需要做的是使用let 在本地定义它们,以便它们在每次循环迭代时获得新的绑定。

看一个简单的例子来演示这里发生了什么:

for (var i = 0; i < 4; i++) {
  x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

这不好,因为x 是一个全局变量。现在var:

for (var i = 0; i < 4; i++) {
  var x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

仍然不好,因为每次迭代都共享一个 x 绑定。现在let:

for (var i = 0; i < 4; i++) {
  let x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

之所以有效,是因为每次迭代都会获得一个新的绑定。

更新

另一件事是确保您知道每个request.post 何时结束,以便您可以在正确的时间发送回复。

您可以使用async 来帮助您。您可以使用诸如 BluebirdQ 之类的 Promise 和库来帮助您。但你也可以做一个简单的把戏。如果您想知道您在我上面展示的示例的最后一个回调中,您可以像这样计算调用:

let current = 0, last = 0;
for (let i = 0; i < 4; i++) {
  let x = 'Number ' + i;
  setTimeout(function () {
    if (++current === last) console.log('Last callback:');
    console.log(x);
  }, 500*i);
  last++;
}

这可能不是处理复杂情况的最佳方式,但它展示了正在发生的事情:last 变量在每次迭代时递增,并且回调仅在那时注册。然后回调开始一个接一个地触发,您可以在每次触发 ne 回调时递增 current 变量,并比较是否是最后一个。

现在,一般建议:每次都使用let(或const)而不是var。它的工作方式更加直观。当然,如果您知道自己在做什么,您可以使用var,但如果有疑问,请使用let

【讨论】:

  • 感谢@rsp。所以如果我使用let,你认为这会起作用吗,还是我也需要开始添加回调?
  • 如果我使用let,那么我需要使用strict mode,但我需要users 作为全局变量,因为我在我的两个快速端点中使用它。有意义吗?
  • @phantom 将let 用于nameuserId 和可能的i 是一个开始。另一个问题是 console.log(users)res.send 需要在所有回调结束后发生。
  • 对于全局变量,您可以在两个处理程序之外使用global.users 或定义usersvar userslet users,就像在文件开头一样。如果处理程序位于单独的文件中,那么您可以在他们俩共同的 required 文件中执行此操作。
  • @phantom 我更新了我的答案,提供了一些关于如何确保自己处于最后一个回调中并且可以返回响应的想法。最优雅的方法是使用async 或primise 来处理类似的情况,但您也可以计算回调的调用次数,并在回调结束时使用if (++current === last) 技巧来运行console.log(users)。超时将起作用,但如果由于某种原因并非所有请求都在这 3 秒内完成,那么如果您使用超时,您将打印不完整的数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-13
  • 1970-01-01
  • 2021-05-12
  • 1970-01-01
相关资源
最近更新 更多