带有请求承诺的 NodeJS 发布请求以进行 Twitch 身份验证

Posted

技术标签:

【中文标题】带有请求承诺的 NodeJS 发布请求以进行 Twitch 身份验证【英文标题】:NodeJS Post Request with Request Promise for Twitch Authentication 【发布时间】:2019-03-18 05:58:15 【问题描述】:

我正在尝试通过 Twitch 登录在我的应用上对用户进行身份验证。我似乎无法正确获得request.post()(使用请求承诺)。我尝试了许多不同的变体,并且通常在服务器日志中收到“未处理的拒绝”。这方面的 Twitch API 指南是 here。 POST 响应应该是 JSON。这是我的最新版本:

const twitchATParams =
'?client_id=' + twitchAppClientId +
'&client_secret=' + twitchClientSecret +
'&code=' + code +
'&grant_type=authorization_code' +
'&redirect_uri=' + twitchAppRedirect;

request.post(twitchATRequestUrl + twitchATParams)
.then((accessTokenResponse) => 
    const accessToken = accessTokenResponse.access_token;
    console.log('Got an access token: ' + accessToken);
    res.status(200).send('Got an access token: ' + accessToken);
  )
  .catch((error) => 
    res.status(error.statusCode).send(error.error.error_description);
  );

我也试过这个:

request.post(
url:     twitchATRequestUrl,
form:     client_id: twitchAppClientId,
           client_secret: twitchClientSecret,
           code: code,
           grant_type: "authorization_code",
           redirect_uri:  twitchAppRedirect
, function(error, accessTokenResponse, body)
  const accessToken = accessTokenResponse.access_token;
  console.log('Got an access token: ' + accessToken);
  res.status(200).send('Got an access token: ' + accessToken);
);

这是 Twitch API 指南说我需要做的,我想我在将其翻译成 javascript 时遇到了麻烦:

POST https://id.twitch.tv/oauth2/token
  ?client_id=<your client ID>
  &client_secret=<your client secret>
  &code=<authorization code received above>
  &grant_type=authorization_code
  &redirect_uri=<your registered redirect URI>

更新: 该应用使用 Cloud Functions 托管在 Firebase 上。也许这会影响我的请求?

更新 2: 据此:Deployed Firebase Function Cannot Execute HTTP GET to external API? 我只能在 Firebase 付费计划上发出外部 API 请求。我假设这是我的问题。我将升级到现收现付计划(实际上免费提供大量数据),然后再试一次并在此处发布我的结果。

【问题讨论】:

你使用的是哪个请求模块? 我正在使用 request-promise。 我建议尝试一下node-fetch。在过去的 8 年中,请求并没有稳定到足以让我考虑的程度。它不断地破坏东西。 【参考方案1】:

我不知道你用的是什么库,但最后一个例子和这个版本很相似:https://www.npmjs.com/package/request。

如果是那个版本,问题是您错误地映射了回调的参数。 accessTokenResponse var 是响应对象,而不是您想要的 JSON。您必须像这样解析 body 参数。

function(error, response, body)
    console.log(JSON.parse(body));

【讨论】:

我正在使用 request-promise 但它应该包含所有正常的“请求”功能对吗?我尝试了您的建议,但仍然收到 Unhandled Rejection 错误,它还显示“SyntaxError: Unexpected token u in JSON at position 0”和“RequestError: Error: getaddrinfo ENOTFOUND id.twitch.tv id.twitch.tv:443在新的请求错误”。我似乎对 Twitch 的服务器的 POST 请求有问题。 我已使用 Twitch API 指南中有关此 POST 请求的信息更新了问题,以帮助澄清。 您提到的错误与DNS解析有关。我在另一条评论中读到您正在使用 Cloud Functions,对吗?所以,大概是暴露云函数的方式让我试试吧。 没关系是您当前的 Firebase 计划来请求另一个 API,您必须选择一个非免费计划。 ***.com/questions/42774807/…【参考方案2】:

我认为您使用 request-promise 的方式是错误的。试试这个吧。

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

API 函数内部:

const twitchATParams =
'?client_id=' + twitchAppClientId +
'&client_secret=' + twitchClientSecret +
'&code=' + code +
'&grant_type=authorization_code' +
'&redirect_uri=' + twitchAppRedirect;


var options = 
    method: 'POST',
    uri: twitchATRequestUrl + twitchATParams,
    /* qs: 
        access_token: 'xxxxx xxxxx' // -> uri + '?access_token=xxxxx%20xxxxx'
    , */ //you can pass params here too
    json: true // Automatically stringifies the body to JSON
;

rp(options)
    .then(function (response) 
        res.status(200).send('Got an access token: ' + response.accessToken);
    )
    .catch(function (err) 
        // Post failed...
    );

【讨论】:

也试过了。仍然得到“未处理的拒绝”和“RangeError: Invalid status code: 0 at ServerResponse.writeHead”。这是否与此应用程序使用 Cloud Functions 托管在 Firebase 上这一事实有关?这会以某种方式影响请求或响应吗? 您是否尝试过使用像 Postman 这样的客户端调用 API?是否按预期工作? 我不熟悉 Postman。我可以调用 API 并获得此 Oauth 身份验证第一步的响应,我只是在我的示例中没有该代码。这只是这个问题所涉及的第二步,这给我带来了问题。【参考方案3】:

解决了。事实证明,我确实需要付费计划(Blaze,即用即付)来访问外部 API。我升级了,基本上解决了这个问题。它让我看到了一个新的错误代码:StatusCodeError: 400 - "\"status\":400,\"message\":\"Parameter redirect_uri does not match registered URI\",所以我发现我的代码中的重定向 URL 丢失了“/callback”(Twitch 应用程序管理设置上的 OAuth 重定向 URL 末尾有这个“/callback”)。

我也能够使用这两个代码块成功获取访问令牌:

const twitchTokenPayload = 
  client_id: twitchAppClientId,
  client_secret: twitchClientSecret,
  code: code,
  grant_type: 'authorization_code',
  redirect_uri: twitchAppRedirect,
;

request.post(twitchATRequestUrl,  json: twitchTokenPayload )
  .then((accessTokenResponse) => 
    const accessToken = accessTokenResponse.access_token;
    console.log('Got an access token: ' + accessToken);
    res.status(200).send('Got an access token: ' + accessToken);
  )
  .catch((error) => 
    console.log('Caught error: ' + error.error.error_description);
    res.status(error.statusCode).send(error.error.error_description);
  );

这也有效:

request.post(
url:     twitchATRequestUrl,
form:     client_id: twitchAppClientId,
           client_secret: twitchClientSecret,
           code: code,
           grant_type: "authorization_code",
           redirect_uri:  twitchAppRedirect
, function(error, response, body)
  console.log(JSON.parse(body));
  const jsonStuff = JSON.parse(body);
  const accessToken = jsonStuff.access_token;
  console.log('Got an access token: ' + accessToken);
  res.status(200).send('Got an access token: ' + accessToken);
);

【讨论】:

以上是关于带有请求承诺的 NodeJS 发布请求以进行 Twitch 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Azure 函数内部发出基于承诺的 HTTP 发布请求 (NodeJS)?

NodeJS 和 Electron - 后端的请求承诺冻结前端的 CSS 动画

用 Jest 模拟基于承诺的请求

带有请求承诺的异步/等待返回未定义

可能的未处理承诺拒绝(id:1):TypeError:网络请求失败

带有 Q 承诺的 Node.JS 猫鼬请求返回空