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