如何为 Google Calendar API 批量请求指定 `quotaUser`?

问题描述 投票:0回答:3

我有一个服务器端 NodeJS 应用程序,它使用具有域委托的 Google 服务帐户,通过 Google 日历 API 批处理端点代表其他用户创建 Google 日历事件。

因为我尝试创建超过 600 个事件/分钟(我当前的“每个用户每分钟查询数”限制),所以我想指定其他用户来收取配额,如 使用服务帐户进行正确记帐中所述Google Calendar API 文档中“管理配额”一文的 部分指出:

如果您的应用程序使用域范围委派执行请求,则默认情况下,服务帐户将根据“每个用户每个项目每分钟”配额收费,而不是您模拟的用户。这意味着服务帐户可能会用完配额并受到速率限制,即使它可能在多个用户的日历上运行。您可以通过使用quotaUser URL参数(或x-goog-quota-user HTTP标头)来指示将向哪个用户收费来避免这种情况。这仅用于配额计算。

该文档还链接到 Google Cloud API“限制 API 使用”一文中的限制每个用户的请求,其中指出:

为了防止个人用户用完您的 API 配额,某些 API 包含默认的每用户每分钟限制。如果存在这样的默认限制,您可以按照上一节所述修改该值,以限制每个用户可用的配额。

个人用户由唯一的字符串标识。如果您要创建代表用户发出请求的服务器端应用程序(其中调用代码托管在您拥有的服务器上),则您的请求必须包含quotaUser参数。

要识别用户,请使用quotaUser=userID 参数。该值仅用于短期配额强制执行,因此您不需要使用真实的用户 ID。您可以选择长度不超过 40 个字符的任意字符串来唯一标识用户。

quotaUser 参数仅用于限制每个用户每分钟的请求数。如果您不发送quotaUser参数,则所有调用都将归因于您的服务器计算机,在这种情况下,用户无法限制调用。

但是,无论我如何尝试在请求中包含

quotaUser
,只要我在一分钟内发出超过 600 个请求,我就会开始收到如下所示的 403 错误,这表明
quotaUser
值被忽略:

{
  "body": {
  "error": {
    "code": 403,
    "message": "Quota exceeded for quota metric 'Queries' and limit 'Queries per minute per user' of service 'calendar-json.googleapis.com' for consumer 'project_number:xxxxxxxxxxx'.",
    "errors": [
      {
        "message": "Quota exceeded for quota metric 'Queries' and limit 'Queries per minute per user' of service 'calendar-json.googleapis.com' for consumer 'project_number:xxxxxxxxxxx'.",
        "domain": "usageLimits",
        "reason": "rateLimitExceeded"
      }
    ]
    "status": "PERMISSION_DENIED",
    "details": [
      {
         "@type": "type.googleapis.com/google.rpc.ErrorInfo",
         "reason": "RATE_LIMIT_EXCEEDED",
         "domain": "googleapis.com",
         "metadata": {
           "service": "calendar-json.googleapis.com",
           "quota_limit": "defaultPerMinutePerUser",
           "quota_metric": "calendar-json.googleapis.com/default",
           "consumer": "projects/xxxxxxxxxxx"
        }
      }
   ]
  }
}

无法找到如何包含quotaUser参数的具体示例,我尝试了所有可以想到的组合,但都无济于事,包括(并确保为每个请求改变传递给quotaUser的实际值):

在请求部分url的查询字符串中:

POST https://www.googleapis.com/batch/calendar/v3 HTTP/1.1
Authorization: /*Auth token*/
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <xxx>

POST /calendar/v3/calendars/primary/events?quotaUser=usernamemydomaincom
Content-Type: application/json


{{ body }}

--batch_foobarbaz--

在请求部分:

POST https://www.googleapis.com/batch/calendar/v3 HTTP/1.1
Authorization: /*Auth token*/
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <xxx>

POST /calendar/v3/calendars/primary/events
Content-Type: application/json
quotaUser: usernamemydomaincom

{{ body }}

--batch_foobarbaz--

在请求部分使用标头名称格式:

POST https://www.googleapis.com/batch/calendar/v3 HTTP/1.1
Authorization: /*Auth token*/
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <xxx>

POST /calendar/v3/calendars/primary/events
Content-Type: application/json
X-Goog-Quota-User: usernamemydomaincom


{{ body }}

--batch_foobarbaz--

以及对批处理端点本身的请求

POST https://www.googleapis.com/batch/calendar/v3?quotaUser=usernamemydomaincom HTTP/1.1
Authorization: /*Auth token*/
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <xxx>

POST /calendar/v3/calendars/primary/events
Content-Type: application/json

{{ body }}

--batch_foobarbaz--

POST https://www.googleapis.com/batch/calendar/v3 HTTP/1.1
Authorization: /*Auth token*/
Content-Type: multipart/mixed; boundary=batch_foobarbaz
X-Goog-Quota-User: usernamemydomaincom

--batch_foobarbaz
Content-Type: application/http
Content-ID: <xxx>

POST /calendar/v3/calendars/primary/events
Content-Type: application/json

{{ body }}

--batch_foobarbaz--

如何正确提供

quotaUser
参数,以便不受每个用户每分钟 600 个请求的限制?

google-api google-calendar-api
3个回答
2
投票

如果您正在寻找示例,您可以查看 Node JS 库文档中的 全局选项

const {google} = require('googleapis');
google.options({
  // All requests from all services will contain the above query parameter
  // unless overridden either in a service client or in individual API calls.
  params: {
    quotaUser: '[email protected]'
  }
});

但是,当您获得

RATE_LIMIT_EXCEEDED
时,另一种解决方案是按照文档中的建议实施指数退避


0
投票

我也在寻找同样的答案。您是否尝试过使用 principal 作为值而不是电子邮件地址?我怀疑 40 个字符的限制暗示这正是他们所期望的。也许?

我们会尝试,如果发现的话我们会在这里更新!


0
投票

当传递主要用户时,quotaUser 将被忽略。看 quotaUser 是如何工作的? 为了超过 600 个用户配额限制,您可能必须在对日历进行 api 调用之前模拟不同的用户。

const newAuths = userIds.map(
    (userId) =>
      new google.auth.JWT({
        email: authProp.email, //service account
        key: authProp.key,  
        scopes: SCOPES,
        subject: userId,   //<===This helped
      })
  );
// Now you can make 600 call with newAuths[0]
// and next 600 with newAuths[1] and so on,
// till you reach 10,000 upper limit set for you app.
© www.soinside.com 2019 - 2024. All rights reserved.