Skip to main content

此版本的 GitHub Enterprise 已停止服务 2022-10-12. 即使针对重大安全问题,也不会发布补丁。 为了获得更好的性能、更高的安全性和新功能,请升级到最新版本的 GitHub Enterprise。 如需升级帮助,请联系 GitHub Enterprise 支持

集成者最佳实践

构建一个能够可� 地与 GitHub Enterprise Server API 进行交互并为您的用户提供最佳体验。

有兴趣与 GitHub 平台集成吗? � 有很多同伴。 本指南将帮助� 构建能够为用户提供最佳体验并确保与 API 进行可� 交互的应用。

确保安全接收从 GitHub 交付的有效负载

请务必保护从 GitHub 发送的有效负载。 虽然有效负载中不会� 输个人信息(如密� �),但泄露任何信息总是不好的。 有些信息可能比较敏感,包括提交者电子邮件地址或私有仓库的名称。

您可以采取以下� 个步骤来确保安全接收由 GitHub 交付的工作负载:

  1. 确保您的接收服务器在 HTTPS 连接上。 默认情况下,GitHub 在交付有效负载时会验证 SSL 证书。
  2. 提供密钥令牌以确保有效负载肯定来自 GitHub。 通过实施密钥令牌,您可以确保服务器接收的任何数据绝对来自 GitHub。 理想情况下,� 应该为� 的服务的每个用户都提供一个不同的密钥令牌。 这� �,即使某个令牌被泄露,也不至于影响其他用户。

支持异步工作而非同步工作

GitHub 要求在收到 Webhook 有效负载后 30 秒内做出集成响应。 如果您的服务需要更长的时间才能完成,则 GitHub 将终止连接,并且有效负载将丢失。

由于� 法预测您的服务完成速度,� 此您应该在后台作业中执行所有“实际工作”。 Resque(用于 Ruby)、RQ(用于 Python)或 RabbitMQ(用于 Java)是可以处理后台作业的排队和处理的库的示例。

请注意,即使后台作业正在运行,GitHub 仍要求� 的服务器能够在三十秒内做出响应。 您的服务器需要通过发送某种响应来确认它收到了有效负载。 您的服务必须尽快对有效负载执行任何验证,以便您能够准确地报告您的服务器是否会继续处理请求。

响应 GitHub 时使用适当的 HTTP 状态代� �

每个 web 挂钩都有自己的“最近交付”部分,其中列出了部署是否成功。

最近交付视图

您应该使用适当的 HTTP 状态代� �来通知用户。 � 可以使用 201202 等代� �来确认收到了不会被处理的有效负载(例如,非默认分支交付的有效负载)。 针对灾难性故障预留 500 错误代� �。

向用户提供尽可能多的信息

用户可能会深入� �究您发回 GitHub 的服务器响应。 请确保您的信息清晰明了。

查看有效负载响应

遵循 API 发送给您的任何重定向

GitHub 在资源发生移动时会通过提供重定向状态代� �来明确告诉您。 您应该遵循这些重定向。 每个重定向响应都使用要转到的新 URI 来设置 Location � �头。 如果您收到了重定向,最好更新代� �以遵循新的 URI,以防您请求我们可能已� 除的� 效路径。

我们提供了 HTTP 状态代� �列表,� 在设计应用以遵循重定向时需要注意这些代� �。

不要手动解析 URL

通常,API 响应包含 URL 形式的数据。 例如,当请求存储库时,我们会发送一个名为 clone_url 的键,其中包含可用来克隆存储库的 URL。

为了应用程序的稳定性,您不应该尝试解析此数据,或者尝试猜测并构� 未来 URL 的� �式。 否则,如果我们决定更改该 URL,您的应用程序可能会中断。

例如,在处理分页结果时,人们往往很想构� 在末尾追�  ?page=<number> 的 URL。 要抑制这种冲动。 我们的分页指南提供了一些关于可� 跟踪分页结果的安全提示。

在处理事件之前检查事件类型和操作

有多种 Webhook 事件类型,并且每个事件可以有多个操作。 随着 GitHub 功能集的增长,我们会不时添� 新的事件类型或向现有事件类型添� 新的操作。 请确保您的应用程序在进行任何 web 挂钩处理之前明确检查事件的类型和操作。 X-GitHub-Event 请求� �头可用于了解收到了哪个事件,以便进行适当处理。 同� �,有效负载具有顶层 action 键,可用于了解对相关对象采取了哪些操作。

例如,如果� 已将 GitHub Webhook 配置为“向我发送所有内容”,则在添� 新的事件类型和操作时,� 的应用程序就会开始接收它们。 � 此,不建议使用任何类型的 catch-all else 子句。 以下面的代� �为例:

# Not recommended: a catch-all else clause
def receive
  event_type = request.headers["X-GitHub-Event"]
  payload    = request.body

  case event_type
  when "repository"
    process_repository(payload)
  when "issues"
    process_issues(payload)
  else
    process_pull_requests
  end
end

在此代� �实例中,如果收到 repositoryissues 事件,将会正确调用 process_repositoryprocess_issues 方法。 但是,任何其他事件类型都会导致调用 process_pull_requests。 当添� 新的事件类型时,这将导致不正确的行为 - 将以处理 pull_request 事件的方式来处理新的事件类型。

� 此,我们建议明确检查事件类型并采取相应行动。 在以下代� �示例中,我们明确检查 pull_request 事件,而 else 子句仅记录我们已收到新事件类型:

# Recommended: explicitly check each event type
def receive
  event_type = request.headers["X-GitHub-Event"]
  payload    = JSON.parse(request.body)

  case event_type
  when "repository"
    process_repository(payload)
  when "issues"
    process_issue(payload)
  when "pull_request"
    process_pull_requests(payload)
  else
    puts "Oooh, something new from GitHub: #{event_type}"
  end
end

由于每个事件也可以有多个操作,� 此建议对操作进行类似的检查。 例如,IssuesEvent 有多个可能的操作。 其中包括创建问题时的 opened、关闭问题时的 closed 以及将问题分配给某人时的 assigned

与添� 事件类型一� �,我们可以向现有事件添� 新操作。 � 此,再次强调,在检查事件的操作时不要使用任何类型的 catch-all else 子句。 相反,我们建议像检查事件类型一� �明确检查事件操作。 下面的示例非常吻合我们在上文中针对事件类型的建议:

# Recommended: explicitly check each action
def process_issue(payload)
  case payload["action"]
  when "opened"
    process_issue_opened(payload)
  when "assigned"
    process_issue_assigned(payload)
  when "closed"
    process_issue_closed(payload)
  else
    puts "Oooh, something new from GitHub: #{payload["action"]}"
  end
end

在此示例中,在调用 process_closed 方法之前会先检查 closed 操作。 任何未识别的操作都会被记录以供将来参考。

处理 API 错误

尽管您的代� �从未引入漏洞,但您可能会发现在尝试访问 API 时遇到连续错误。

� 应该确保与 API 正确交互,而不是忽略重复的 4xx5xx 状态代� �。 例如,如果某个终结点请求一个字符串,而� 向其� 递一个数值,则� 将会收到 5xx 验证错误,并且� 的调用不会成功。 同� �,试图访问未经授权或不存在的终结点会导致 4xx 错误。

故意忽略重复的验证错误可能会导致您的应用程序� 滥用而被暂停。