注意
只有当站点管理员启用了速率限制时,才会为实例启用速率限制。 即使实例禁用了速率限制,你可能仍希望遵循最佳做法,以避免超出速率限制。 这有助于减少服务器上的负载。
避免轮询
应订阅 Webhook 事件,而不是通过轮询 API 来获取数据。 这有助于将集成保持在 API 速率限制内。 有关详细信息,请参阅“Webhooks 文档”。
如果无法使用 Webhook,并且必须轮询 API,请尽可能高效地轮询以避免超出速率限制:
- 只需按实际需要的频率,按照固定计划进行轮询。 如果响应包含一个
x-poll-interval标头,请至少等待那么多秒,然后再轮询同一终结点。 - 发出经过身份验证的条件请求,使未更改的数据不计入主要速率限制。 有关详细信息,请参阅 “使用条件请求”。
- 只请求所需的数据,并保持响应稳定,以便让更多轮询返回
304 Not Modified。 有关详细信息,请参阅 “发出可缓存的请求”。
发出经身份验证的请求
经身份验证的请求的主要速率限制高于未经身份验证的请求。 为避免超出速率限制,应发出经过身份验证的请求。 有关详细信息,请参阅“REST API 的速率限制”。
避免并发请求
为避免超出辅助速率限制,应采用串行方式发出请求,而不是并行发出请求。 为此,可以为请求实施队列系统。
在可变请求之间暂停
如果要发出大量的 POST、PATCH、PUT 或 DELETE 请求,则请求之间至少应间隔一秒钟。 这将帮助您避免次级速率限制。
恰当处理速率限制错误
如果收到速率限制错误,应当根据以下指导原则暂时停止发出请求:
- 如果有
retry-after响应头,则应先等待数秒,然后再尝试请求。 - 如果
x-ratelimit-remaining标头为0,应在x-ratelimit-reset标头指定的时间之后再尝试发出另一个请求。 标头x-ratelimit-reset以 UTC 纪元秒为单位。 - 否则,请在重试之前等待至少一分钟。 如果您的请求因二级速率限制而持续失败,请在每次重试之间等待呈指数级增长的时间,并在达到特定重试次数后抛出一个错误。
如果在受到速率限制的情况下继续发出请求,可能会导致禁止集成。
跟随重定向
GitHub REST API 在适当情况下使用 HTTP 重定向。 应假定任何请求都可能会导致重定向。 收到 HTTP 重定向不代表出现错误,应遵循该重定向。
301 状态代码指示永久重定向。 应将请求重复到 location 标头指定的 URL。 此外,应更新代码以将此 URL 用于之后的请求。
302 或 307 状态代码指示临时重定向。 应将请求重复到 location 标头指定的 URL。 但是,不应更新代码以将此 URL 用于之后的请求。
可能会根据 HTTP 规范使用其他重定向状态代码。
请勿手动分析 URL
许多 API 终结点会在响应正文中返回字段的 URL 值。 不应尝试分析这些 URL 或预测之后 URL 的结构。 如果 GitHub 将来更改 URL 的结构,这可能会导致集成中断。 相反,应查找包含所需信息的字段。 例如,创建问题的终结点会返回一个 html_url 字段,其值类似 https://github.com/octocat/Hello-World/issues/1347,以及 number 字段,其值类似 1347。 如果需要知道问题的数量,请使用 number 字段,而不是分析 html_url 字段。
同样,不应尝试手动构造分页查询。 而是应使用链接标头来确定可以请求的结果页。 有关详细信息,请参阅“在 REST API 中使用分页”。
使用条件请求
大多数终结点会返回 etag 标头,许多终结点会返回 last-modified 标头。 可以使用这些标头的值发出条件 GET 请求。 如果响应未更改,将收到 304 Not Modified 响应。 在正确使用 304 标头授权的情况下发出条件请求时,如果返回 Authorization 响应,则该请求不计入主速率限制。 这会使条件请求在轮询终结点时特别有用,因为每个 304 Not Modified 响应都很快且不使用速率限制。
在以下示例中,请将 YOUR-TOKEN 替换为您的访问令牌。 将 REPO-OWNER 替换为拥有该存储库的帐户,并将 REPO-NAME 替换为该存储库的名称。
要使用 etag 发出条件请求:
-
发送请求并保存响应中
etag标头的值。curl --include --header "Authorization: Bearer YOUR-TOKEN" http(s)://HOSTNAME/api/v3/repos/REPO-OWNER/REPO-NAME/pulls响应包括标头
etag:HTTP/2 200 etag: "644b5b0155e6404a9cc4bd9d8b1ae730" -
在下一次向同一 URL 发出的请求中,在
if-none-match标头中发送已保存的值。curl --include --header "Authorization: Bearer YOUR-TOKEN" --header 'if-none-match: "644b5b0155e6404a9cc4bd9d8b1ae730"' http(s)://HOSTNAME/api/v3/repos/REPO-OWNER/REPO-NAME/pulls如果数据未更改,将收到响应
304 Not Modified,该响应不计入主要速率限制:HTTP/2 304
还可以使用 last-modified 标头。 例如,如果上一个请求返回 last-modified 标头,值为 Wed, 25 Oct 2023 19:17:59 GMT,则可以在之后的请求中使用 if-modified-since 标头:
curl --include --header "Authorization: Bearer YOUR-TOKEN" --header 'if-modified-since: Wed, 25 Oct 2023 19:17:59 GMT' http(s)://HOSTNAME/api/v3/repos/REPO-OWNER/REPO-NAME
除非特定终结点的文档另有说明,否则不支持对不安全方法(例如 POST、PUT、PATCH 和 DELETE)的条件请求。
发出可缓存的请求
条件请求仅在终结点返回 304 Not Modified时节省时间和速率限制。 当请求的表示形式自保存其304或etag值以来未更改时,终结点将返回last-modified;不相关的响应标头(如日期)仍可能有所不同。 若要在轮询时更有可能获得 304 响应,请使请求保持稳定且具体。
仅请求所需的数据。 较小的、更具体的响应更改频率较低,因此返回 304 Not Modified 的频率更高。 例如,若要检查一个分支的拉取请求,请按该分支筛选列表,而不是列出每个拉取请求并自行搜索结果。 将 HEAD-OWNER 替换为拥有头分支的帐户;对于来自派生仓库的拉取请求,该帐户是拥有该派生仓库的帐户。 用分支名称替换 BRANCH-NAME,如果该名称包含特殊字符(例如 # 或 &),请对其进行 URL 编码:
curl --include --header "Authorization: Bearer YOUR-TOKEN" "http(s)://HOSTNAME/api/v3/repos/REPO-OWNER/REPO-NAME/pulls?head=HEAD-OWNER:BRANCH-NAME"
如果浏览列表,请使用稳定的排序顺序。 每当项发生更改时,某些参数(例如 sort=updated)对列表重新排序。 当项移动到新位置时,其旧位置与新位置之间的项将转移到不同的页面上,以便已提取的页面可以返回新数据,而不是 304 Not Modified。 稳定的顺序(如默认值)会停止对现有项的更新重新排序,尽管添加或删除项仍可将条目转移到其他页面上。
每次轮询相同的数据时,都使用相同的参数。 不同的页面大小、页码或筛选器会产生包含不同 etag 的不同响应。
请勿忽略错误
不应忽略重复的 4xx 和 5xx 错误代码。 相反,应确保与 API 正确进行交互。 例如,如果某个终结点请求字符串,而你向其传递一个数值,则你将会收到验证错误。 同样,试图访问未经授权或不存在的终结点会导致 4xx 错误。
如果要轮询,并且资源重复返回 404 Not Found 响应,请不要在每次轮询时继续请求它。 首先,请确保 404 不是由身份验证或授权问题引起的。 对于某些私有资源,当你的凭据不授予访问权限时,GitHub 返回的是 404 Not Found 响应,而不是 403 Forbidden 响应,因此,404 并不总是意味着该资源不存在。 有关详细信息,请参阅“REST API 故障排除”。 确认凭据正确后,请等待更长时间,然后再次检查,或仅当有理由相信资源现在存在时,才再次检查。 重复请求缺少的资源会浪费速率限制,并可以触发辅助速率限制。
故意忽略重复的验证错误可能会导致您的应用程序因滥用而被暂停。