【问题标题】:JavaScript for...of, for...in, or other iterative methods are not working for multiple API callsJavaScript for...of、for...in 或其他迭代方法不适用于多个 API 调用
【发布时间】:2018-09-22 04:20:45
【问题描述】:

我的目标是通过传递视频 ID 从 Brightcove CMS API 获取有关视频的元数据。

我们的视频元数据存储在四个不同的业务部门(或配置文件)中,因此我必须分别查询每个业务部门的端点。不知道在哪个事业部会查到哪个视频ID。每次通话我最多可以发送 10 个视频 ID。以下是按视频 ID 获取视频元数据所需的步骤。

1) 获取访问权限token(此步骤使用我提供的客户端凭据)。

2) 通过 options 参数将访问权 token 传递给请求对象 (sendRequest)。

3) 解析响应并将其放入全局videosArray

4) 对每组 10 个或更少的唯一视频 ID(由多维数组表示)重复步骤 1 到 3。

5) 为每个视频帐户(业务部门)重复步骤 1 到 4。

仅供参考:boilerplate code from Brightcove 使用回调。我已经将该代码转换为异步/等待。如果我的 async/await 代码不正确,也许有人也可以提出改进建议。

我正在使用 Node 8.10ES6+request-promise-native 模块(以及其他)。任何看似隐式声明的变量都在全局范围内声明。我只是没有在这里粘贴它们。

bizUnit 是一个对象数组(我总共有四个不同的业务单元要迭代):

businessUnits = [
     bizUnitOne: {
          account_id: 'uhdafoia98243r2',
          client_id: 'oidahf982y229hr',
          client_secret: 'iuahf9o4398oyg',
          player_url: 'afdhy984wyyfsg',
     },
     bizUnitTwo: {
          account_id: 'uhdafoia98243r2',
          client_id: 'oidahf982y229hr',
          client_secret: 'iuahf9o4398oyg',
          player_url: 'afdhy984wyyfsg',
     }
]

获取访问令牌函数声明:

async function getAccessToken(bizUnit) {
// base64 encode the client_id:client_secret string for basic auth
let bodyObj,
    token;
authString = new Buffer(bizUnit.client_id + ':' + bizUnit.client_secret).toString('base64');
let payLoad = {
    method: 'POST',
    url: 'https://oauth.brightcove.com/v3/access_token?grant_type=client_credentials',
    headers: {
        'Authorization': 'Basic ' + authString,
        'Content-Type': 'application/json'
    },
    json: true
};
try {
    let result = await request(payLoad);
    bodyObj = await JSON.parse(result);
    token = bodyObj.access_token;
    return token;
}
catch (error) {
    console.log(oauthError, error);
}

}

发送请求声明:

async function sendRequest(options) {
let requestOptions = {
    method: 'GET',
    url: options.url,
    headers: {
        'Authorization': 'Bearer ' + options.token,
        'Content-Type': 'application/json'
    },
    json: true
};
let makeRequest = async (reqOptions) => {
    try {
        let body = await request(reqOptions);
        return JSON.parse(body);
    } catch (error) {
        console.log(apiError, error);
    }
};
// make the request
await makeRequest(requestOptions);

}

视频 IDs 数组示例(理论上,该数组可以包含成百上千个视频 ID,分块为 10 或更少):

videoIdsGroup = [ [53245,2352,243252,2352352,234234,234324,2342342,24242,23542,234324], [43534, 34543, 3453, 3453345] ];

将所有内容放在一起并提出请求:

function setUpVideoRequest(bizUnit) {
(async (bu) => {
    // note that access tokens live for 5 minutes
    // but you can always request one for each call to be safe

    for (let videoIdsArr of videoIdsGroup) {
        let endPoint,
        videoIdsString = videoIdsArr.join();
        endPoint = '/accounts/' + bu.account_id + '/videos/' + videoIdsString + '&sort=' + sort;
        options.url = baseURL + endPoint;
        options.token = await getAccessToken(bizUnit);
        const videos = await sendRequest(options);
        videosArray = videosArray.concat(videos);
    }
})(bizUnit);

}

开始执行:

   for (let bu of businessUnits) {

        /*the counter below is to reveal how many times and in what sequence this for...of loop is executing. my console.log indicates that this loop iterates through all businessUnits immediately, but then it runs again and eventually succeeds in some of the calls and repeats those calls even though it already got data.*/ 
        let parentCounter = 0;
        console.log("BizUnit COUNTER", parentCounter++);

        try {
    promises.push(setUpVideoRequest(bu));
} catch (error) {
    throw error;
}

}

我收到错误消息(此消息重复,然后我偶尔获取一些数据,然后错误再次重复):

    statusCode: 400,
  message: '400 - {"error":"invalid_client","error_description":"The "client_id" parameter is missing, does not name a client registration that is applicable for the requested call, or is not properly authenticated."}',

我知道 for...of 循环运行不正确,但我尝试了带有 [i] 迭代器的常规 for 循环,我还尝试了 for...in,并且我已经尝试了每个。它们都不能正常工作。

我只是希望能够按帐户 ID(业务单位)和每个视频数组发出请求,并获取所有视频元数据并通过以下方式将其放入全局 videosArray

Promise.all(promises).then((results) => {
    promiseVidArray.push(results);
});

提前感谢您的帮助和洞察力。

【问题讨论】:

  • 如果你想使用await,你必须有一个promise并且不能使用request回调API。如果您已经在使用request-promise-*,请根本不要传递回调!看看它的文档。
  • 另外,永远不要让async function 接受callback。你应该只await你正在做的异步工作,然后return
  • 如果您不熟悉async/await´ yet, try using promises without any syntactic sugar, i.e. use .then()`,请仅调用
  • @Bergi 谢谢。我已经清理了与 Promise 相关的结构。将编辑原始帖子并添加新版本。仍然面临类似的问题。

标签: javascript node.js asynchronous brightcove request-promise


【解决方案1】:

您在 businessUnits 对象中缺少右括号

businessUnits = [{
     bizUnitOne: {
          account_id: 'uhdafoia98243r2',
          client_id: 'oidahf982y229hr',
          client_secret: 'iuahf9o4398oyg',
          player_url: 'afdhy984wyyfsg',
     },
     bizUnitTwo: {
          account_id: 'uhdafoia98243r2',
          client_id: 'oidahf982y229hr',
          client_secret: 'iuahf9o4398oyg',
          player_url: 'afdhy984wyyfsg',
     }
}]; // <-- Here it is the one you're missing

【讨论】:

  • 谢谢。幸运的是,我的实际代码没有这个问题。我专门为这篇文章输入了那个对象,这就是我搞砸的地方。我的生产代码很好。
【解决方案2】:

在对我的 async/await 语法进行了一些更正后(谢谢@Bergi),我发现了问题的根源:我为 4 个请求中的 3 个发送了不正确的客户端凭据。原因很有趣。我已经在下面详细说明了。

当您在 Brightcove Video Cloud 中创建 API 身份验证密钥时,您需要为该密钥提供一个名称,选择要在该密钥下授权的业务部门,然后选择您希望在这些业务部门下公开的端点。

我为每个业务部门创建了一个密钥,Brightcove 为每个密钥提供了一个唯一的“account_id”、“client_id”、“client_secret”。我立即将它们复制/粘贴到记事本文件中,因为“client_secret”在 5 分钟后消失并且无法检索(您必须删除密钥并创建一个新密钥)。

我今天重新登录 Brightcove 管理面板以确认我的密钥是否正确。令我惊讶的是,所有四个“client_id”都完全相同(我复制/粘贴的客户端 ID 是唯一的)。在我的 API 请求中,我为每个业务部门发送了一个唯一的“client_id”,因为这是 Brightcove 在我创建 API 身份验证密钥时为我提供的。不知何故,它们都发生了变化,并成为所有四个业务部门的完全相同的关键。我仍然不明白为什么或如何发生这种情况。

因此,我对 4 个帐户中的 3 个的请求失败。

【讨论】:

    猜你喜欢
    • 2017-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 2018-03-13
    • 2018-03-19
    • 2017-06-05
    • 2020-06-27
    相关资源
    最近更新 更多