spatie/laravel-github-webhooks

在 Laravel 应用中处理 GitHub webhooks

1.2.3 2024-03-07 07:46 UTC

This package is auto-updated.

Last update: 2024-08-29 07:53:00 UTC


README

Latest Version on Packagist GitHub Workflow Status Check & fix styling Total Downloads

GitHub 可以通过 webhooks 通知您的应用程序事件。这个包可以帮助您处理这些 webhooks。

默认情况下,它将验证所有传入请求的 GitHub 签名。所有有效的调用都将记录到数据库中。该包允许您轻松定义在特定 webhooks 撞击您的应用程序时应调度的作业或事件。

以下是一个这样的作业示例。

namespace App\Jobs\GitHubWebhooks;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;

class HandleIssueOpenedWebhookJob implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    public GitHubWebhookCall $gitHubWebhookCall;

    public function __construct(
        public GitHubWebhookCall $webhookCall
    ) {}

    public function handle()
    {
        // React to the issue opened at GitHub event here

        // You can access the payload of the GitHub webhook call with `$this->webhookCall->payload()`
    }
}

在开始使用此包之前,我们强烈建议您阅读 GitHub 上关于 webhooks 的完整文档

您是视觉学习者吗?

这个 YouTube 直播中,我展示了如何使用包,浏览源代码,并解释了如何测试该包。

支持我们

我们在创建 最佳开源包 上投入了大量资源。您可以通过 购买我们的付费产品之一 来支持我们。

我们非常感激您从家乡给我们寄来明信片,并说明您正在使用我们哪些包。您可以在 我们的联系页面 上找到我们的地址。我们将发布所有收到的明信片在我们的 虚拟明信片墙上

安装

您可以通过 composer 安装此包

composer require spatie/laravel-github-webhooks

您必须使用以下命令发布配置文件

php artisan vendor:publish --provider="Spatie\GitHubWebhooks\GitHubWebhooksServiceProvider" --tag="github-webhooks-config"

这是将要发布到 config/github-webhooks.php 的配置文件内容

use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;
use Spatie\GitHubWebhooks\Jobs\ProcessGitHubWebhookJob;
use Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile;

return [
    /*
     * GitHub will sign each webhook using a secret. You can find the used secret at the
     * webhook configuration settings: https://githubdocs.cn/en/developers/webhooks-and-events/webhooks/about-webhooks.
     */
    'signing_secret' => env('GITHUB_WEBHOOK_SECRET'),

    /*
     * You can define the job that should be run when a certain webhook hits your application
     * here.
     *
     * You can find a list of GitHub webhook types here:
     * https://githubdocs.cn/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads.
     * 
     * You can use "*" to let a job handle all sent webhook types
     */
    'jobs' => [
        // 'ping' => \App\Jobs\GitHubWebhooks\HandlePingWebhook::class,
        // 'issues.opened' => \App\Jobs\GitHubWebhooks\HandleIssueOpenedWebhookJob::class,
        // '*' => \App\Jobs\GitHubWebhooks\HandleAllWebhooks::class
    ],

    /*
     * This model will be used to store all incoming webhooks.
     * It should be or extend `Spatie\GitHubWebhooks\Models\GitHubWebhookCall`
     */
    'model' => GitHubWebhookCall::class,

    /*
     * When running `php artisan model:prune` all stored GitHub webhook calls
     * that were successfully processed will be deleted.
     *
     * More info on pruning: https://laravel.net.cn/docs/8.x/eloquent#pruning-models
     */
    'prune_webhook_calls_after_days' => 10,

    /*
     * The classname of the job to be used. The class should equal or extend
     * Spatie\GitHubWebhooks\ProcessGitHubWebhookJob.
     */
    'job' => ProcessGitHubWebhookJob::class,

    /**
     * This class determines if the webhook call should be stored and processed.
     */
    'profile' => ProcessEverythingWebhookProfile::class,

    /*
     * When disabled, the package will not verify if the signature is valid.
     * This can be handy in local environments.
     */
    'verify_signature' => env('GITHUB_SIGNATURE_VERIFY', true),
];

在配置文件的 signing_secret 键中,您应该添加一个有效的 webhook 密钥。您可以在 GitHub 控制台上的 webhook 配置设置 中找到该密钥。

接下来,您必须使用以下命令发布迁移

php artisan vendor:publish --provider="Spatie\GitHubWebhooks\GitHubWebhooksServiceProvider" --tag="github-webhooks-migrations"

迁移发布后,您可以通过运行迁移来创建 github_webhook_calls

php artisan migrate

最后,注意路由:在仓库的 GitHub webhooks 设置中,您必须配置 GitHub webhooks 应发送到的 URL。在您的应用程序的路由文件中,您必须将该路由传递给 Route::githubWebhooks 路由宏

Route::githubWebhooks('webhook-route-configured-at-the-github-webhooks-settings');

确保在配置 webhook url 时,webhooks 应作为 application/json 发送,而不是作为 application/x-www-form-urlencoded

在幕后,此宏将为由该包提供的控制器注册一个 POST 路由。我们建议将其放在 api.php 路由文件中,这样当 webhook 到来时就不会创建会话,也不需要 CSRF 令牌。

如果您出于任何原因必须在 web.php 路由文件中注册该路由,则必须将该路由添加到 VerifyCsrfToken 中间件的 except 数组中

protected $except = [
    'webhook-route-configured-at-the-github-webhooks-settings',
];

用法

GitHub 将为几种事件类型发送 webhooks。您可以在 GitHub 文档中找到 事件类型的完整列表

GitHub 将为撞击您的应用程序 webhook url 的所有请求签名。此包将自动验证签名是否有效。如果签名无效,则请求可能不是由 GitHub 发送的。

除非出现严重错误,这个包将始终对webhook请求返回一个200响应。发送一个200可以防止GitHub反复发送相同的事件。所有带有有效签名的webhook请求都会记录在github_webhook_calls表中。该表有一个payload列,其中保存了传入webhook的整个负载。

如果签名无效,请求将不会记录在github_webhook_calls表中,而是会抛出一个Spatie\GitHubWebhooks\WebhookFailed异常。如果在webhook请求过程中出现错误,抛出的异常将保存在exception列中。在这种情况下,控制器将发送一个500而不是200

该包提供两种方式来处理webhook请求:您可以选择排队一个作业或监听该包将触发的事件。

使用作业处理webhook请求

如果您希望在特定事件类型到来时执行某些操作,可以定义一个执行该工作的作业。以下是一个此类作业的示例

namespace App\Jobs\GitHubWebhooks;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;

class HandleIssueOpenedWebhookJob implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    public GitHubWebhookCall $gitHubWebhookCall;

    public function __construct(
        public GitHubWebhookCall $webhookCall
    ) {}

    public function handle()
    {
        // do your work here

        // you can access the payload of the webhook call with `$this->webhookCall->payload`
    }
}

我们强烈建议您将此作业设置为可排队,因为这将最小化webhook请求的响应时间。这允许您处理更多的GitHub webhook请求并避免超时。

创建您的作业后,必须在github-webhooks.php配置文件中的jobs数组中注册它。键应该是GitHub事件类型的名称。可选地,您可以让它跟随一个点和事件负载中的动作键的值。

// config/github-webhooks.php

'jobs' => [
    'issues.opened' => \App\Jobs\GitHubWebhooks\HandleIssueOpenedWebhookJob::class, // will be called when issues are opened
    'issues' => \App\Jobs\GitHubWebhooks\HandleIssuesWebhookJob::class, // will be called when issues are opened, created, deleted, ...
    '*' => \App\Jobs\GitHubWebhooks\HandleAllWebhooksJob::class, // will be called when any event/action comes in
],

使用GitHubWebhookCall模型工作

Spatie\GitHubWebhooks\Models\GitHubWebhookCall模型包含一些实用的方法

  • headers():返回一个包含请求上使用的所有头部的Symfony\Component\HttpFoundation\HeaderBag实例
  • eventActionName():返回webhook的事件名称和动作名称,例如issues.opened
  • payload($key = null):返回webhook负载的数组。可选地,您可以传递负载中的一个键,其值是您需要的。对于深层嵌套的值,您可以使用点表示法(例如:$githubWebhookCall->payload('issue.user.login');)。

使用事件处理webhook请求

而不是排队作业以在webhook请求到来时执行某些工作,您可以选择监听该包将触发的事件。每当有效请求击中您的应用程序时,该包将触发一个github-webhooks::<事件名称>事件。

事件的负载将是为传入请求创建的GitHubWebhookCall实例。

让我们看看如何监听此类事件。在EventServiceProvider中,您可以注册监听器。

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'github-webhooks::issues.opened' => [
        App\Listeners\IssueOpened::class,
    ],
];

以下是一个此类监听器的示例

<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;

class IssueOpened implements ShouldQueue
{
    public function handle(GitHubWebhookCall $webhookCall)
    {
        // do your work here

        // you can access the payload of the webhook call with `$webhookCall->payload`
    }
}

我们强烈建议您使事件监听器可排队,因为这将最小化webhook请求的响应时间。这允许您处理更多的GitHub webhook请求并避免超时。

上面的示例只是Laravel中处理事件的一种方式。要了解其他选项,请阅读Laravel处理事件文档

删除已处理的webhook

Spatie\GitHubWebhooks\Models\GitHubWebhookCallMassPrunable。要每天删除所有已处理的webhook,您可以安排此命令。

$schedule->command('model:prune', [
    '--model' => [\Spatie\GitHubWebhooks\Models\GitHubWebhookCall::class],
])->daily();

所有在github-webhooks配置文件的prune_webhook_calls_after_days键中指定的天数之前的模型都将被删除。

高级用法

重试处理webhook

所有进入的 webhook 请求都会写入数据库。在处理 webhook 调用时出现问题时,这一点非常有价值。您可以在调查并修复失败原因后,轻松地重试处理 webhook 调用,例如

use Spatie\GitHubWebhooks\Models\GitHubWebhookCall;
use Spatie\GitHubWebhooks\Jobs\ProcessGitHubWebhookJob;

dispatch(new ProcessGitHubWebhookJob(GitHubWebhookCall::find($id)));

执行自定义逻辑

您可以使用自己的模型来添加一些应该在队列作业调度前后执行的自定义逻辑。您可以通过在 github-webhooks 配置文件中的 model 键指定自己的模型来实现。该类应扩展 Spatie\GitHubWebhooks\ProcessGitHubWebhookJob

以下是一个示例

use Spatie\GitHubWebhooks\Jobs\ProcessGitHubWebhookJob;

class MyCustomGitHubWebhookJob extends ProcessGitHubWebhookJob
{
    public function handle()
    {
        // do some custom stuff beforehand

        parent::handle();

        // do some custom stuff afterwards
    }
}

确定是否处理请求

您可以使用自己的逻辑来决定是否处理请求。您可以通过在 github-webhooks 配置文件中的 profile 键指定自己的配置来实现。该类应实现 Spatie\WebhookClient\WebhookProfile\WebhookProfile

GitHub 有时可能会发送一个 webhook 请求 多次。在这个示例中,我们将确保只有当请求之前没有被处理时才处理请求。

use Illuminate\Http\Request;
use Spatie\WebhookClient\Models\WebhookCall;
use Spatie\WebhookClient\WebhookProfile\WebhookProfile;

class GitHubWebhookProfile implements WebhookProfile
{
    public function shouldProcess(Request $request): bool
    {
        return ! WebhookCall::where('payload->id', $request->get('id'))->exists();
    }
}

更新日志

有关最近更改的更多信息,请参阅 更新日志

测试

composer test

贡献

有关详细信息,请参阅 贡献指南

安全

如果您发现了一个关于安全性的错误,请通过发送邮件至 security@spatie.be 而不是使用问题跟踪器。

鸣谢

许可协议

MIT 许可协议(MIT)。有关更多信息,请参阅 许可文件