spatie / laravel-webhook-server
在Laravel应用程序中发送webhooks
Requires
- php: ^8.0
- ext-json: *
- guzzlehttp/guzzle: ^6.3|^7.3
- illuminate/bus: ^8.50|^9.0|^10.0|^11.0
- illuminate/queue: ^8.50|^9.0|^10.0|^11.0
- illuminate/support: ^8.50|^9.0|^10.0|^11.0
- spatie/laravel-package-tools: ^1.11
Requires (Dev)
- mockery/mockery: ^1.4.3
- orchestra/testbench: ^6.19|^7.0|^8.0
- pestphp/pest: ^1.22|^2.0
- pestphp/pest-plugin-laravel: ^1.3|^2.0
- spatie/test-time: ^1.2.2
- dev-main
- 3.8.1
- 3.8.0
- 3.7.0
- 3.6.0
- 3.5.0
- 3.4.3
- 3.4.2
- 3.4.1
- 3.4.0
- 3.3.0
- 3.2.1
- 3.2.0
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.13.0
- 1.12.0
- 1.11.3
- 1.11.2
- 1.11.1
- 1.11.0
- 1.10.0
- 1.9.3
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.1
- 1.8.0
- 1.7.0
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.0
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.0.2
- 0.0.1
This package is auto-updated.
Last update: 2024-09-12 09:44:16 UTC
README
Webhook是一种让应用向另一个应用提供特定事件信息的方式。两个应用之间的通信方式是通过简单的HTTP请求。
此包允许您轻松配置和发送Laravel应用程序中的webhooks。它支持签名调用、重试调用和退避策略。
如果您需要接收和处理webhooks,请查看我们的laravel-webhook-client包。
支持我们
我们投入了大量资源来创建一流的开放源代码包。您可以通过购买我们的付费产品之一来支持我们。
我们非常感谢您从家乡给我们寄来明信片,并说明您正在使用我们的哪个包。您可以在我们的联系页面上找到我们的地址。我们将发布收到的所有明信片在我们的虚拟明信片墙上。
安装
您可以通过composer安装此包
composer require spatie/laravel-webhook-server
您可以使用以下命令发布配置文件
php artisan vendor:publish --provider="Spatie\WebhookServer\WebhookServerServiceProvider"
这是将在config/webhook-server.php
中发布的文件的内容
return [ /* * The default queue that should be used to send webhook requests. */ 'queue' => 'default', /* * The default http verb to use. */ 'http_verb' => 'post', /* * This class is responsible for calculating the signature that will be added to * the headers of the webhook request. A webhook client can use the signature * to verify the request hasn't been tampered with. */ 'signer' => \Spatie\WebhookServer\Signer\DefaultSigner::class, /* * This is the name of the header where the signature will be added. */ 'signature_header_name' => 'Signature', /* * These are the headers that will be added to all webhook requests. */ 'headers' => [], /* * If a call to a webhook takes longer this amount of seconds * the attempt will be considered failed. */ 'timeout_in_seconds' => 3, /* * The amount of times the webhook should be called before we give up. */ 'tries' => 3, /* * This class determines how many seconds there should be between attempts. */ 'backoff_strategy' => \Spatie\WebhookServer\BackoffStrategy\ExponentialBackoffStrategy::class, /* * This class is used to dispatch webhooks onto the queue. */ 'webhook_job' => \Spatie\WebhookServer\CallWebhookJob::class, /* * By default we will verify that the ssl certificate of the destination * of the webhook is valid. */ 'verify_ssl' => true, /* * When set to true, an exception will be thrown when the last attempt fails */ 'throw_exception_on_failure' => false, /* * When using Laravel Horizon you can specify tags that should be used on the * underlying job that performs the webhook request. */ 'tags' => [], ];
默认情况下,该包使用队列来重试失败的webhook请求。请确保在非本地环境中设置一个除sync
之外的队列。
使用方法
这是调用webhook的最简单方法
WebhookCall::create() ->url('https://other-app.com/webhooks') ->payload(['key' => 'value']) ->useSecret('sign-using-this-secret') ->dispatch();
这将向https://other-app.com/webhooks
发送POST请求。请求正文将是传递给payload
的数组的JSON编码版本。请求将包含一个名为Signature
的标题,其中包含接收应用可以使用来验证负载是否被篡改的签名。分派webhook调用还会触发DispatchingWebhookCallEvent
。
如果接收应用没有以2
开头的响应代码响应,该包将在10秒后重试调用webhook。如果第二次尝试失败,该包将在100秒后尝试最后一次调用webhook。如果该尝试失败,将引发FinalWebhookCallFailedEvent
。
同步发送webhook
如果您想立即(同步)调用webhook,可以使用dispatchSync方法。当使用此方法时,webhook将不会被排队,并将立即运行。这在发送webhook是更大作业的一部分且已经排队的场景中可能很有用。
WebhookCall::create() ... ->dispatchSync();
条件发送webhook
如果您想有条件地分派webhook,可以使用dispatchIf
、dispatchUnless
、dispatchSyncIf
和dispatchSyncUnless
方法
WebhookCall::create() ... ->dispatchIf($condition); WebhookCall::create() ... ->dispatchUnless($condition); WebhookCall::create() ... ->dispatchSyncIf($condition); WebhookCall::create() ... ->dispatchSyncUnless($condition);
签名请求是如何工作的
在设置过程中,通常需要在您的应用和希望接收 webhook 的应用之间生成、存储和共享一个密钥。生成密钥可以使用 Illuminate\Support\Str::random()
实现,但具体方法由您决定。该包将使用密钥对 webhook 调用进行签名。
默认情况下,该包会添加一个名为 Signature
的头,其中包含接收应用可以使用的签名,如果有效负载未被篡改。这是计算该签名的方式
// payload is the array passed to the `payload` method of the webhook // secret is the string given to the `signUsingSecret` method on the webhook. $payloadJson = json_encode($payload); $signature = hash_hmac('sha256', $payloadJson, $secret);
跳过签名请求
我们不推荐这样做,但如果您不想对 webhook 请求进行签名,请调用 doNotSign
方法。
WebhookCall::create() ->doNotSign() ...
调用此方法后,将不会设置 Signature
头。
自定义签名请求
如果您想自定义签名过程,可以创建自己的自定义签名器。签名器是任何实现了 Spatie\WebhookServer\Signer
的类。
该接口看起来是这样的。
namespace Spatie\WebhookServer\Signer; interface Signer { public function signatureHeaderName(): string; public function calculateSignature(array $payload, string $secret): string; }
创建您的签名器后,您可以在 webhook-server
配置文件的 signer
键中指定其类名。然后,您的签名器将在所有 webhook 调用中默认使用。
您也可以为特定的 webhook 调用指定签名器
WebhookCall::create() ->signUsing(YourCustomSigner::class) ... ->dispatch();
如果您想自定义头名称,您不需要使用自定义签名器,但可以更改 webhook-server
配置文件中的 signature_header_name
的值。
重试失败的 webhook
当我们发送 webhook 的应用未能以 2xx
状态码发送响应时,该包将认为调用失败。如果远程应用在 3 秒内没有响应,调用也将被视为失败。
您可以在 webhook-server
配置文件的 timeout_in_seconds
键中配置默认超时时间。或者,您可以像这样覆盖特定 webhook 的超时
WebhookCall::create() ->timeoutInSeconds(5) ... ->dispatch();
当 webhook 调用失败时,我们将重试调用两次。您可以在配置文件的 tries
键中设置我们重试 webhook 调用的默认次数。或者,您可以像这样指定特定 webhook 的重试次数
WebhookCall::create() ->maximumTries(5) ... ->dispatch();
为了不频繁地打击远程应用,我们将在每次尝试之间等待一段时间。默认情况下,我们在第一次和第二次尝试之间等待 10 秒,在第三次和第四次尝试之间等待 100 秒,在第四次和第五次尝试之间等待 1000 秒,依此类推。我们将等待的最长时间是 100000 秒,大约是 27 小时。这种行为在默认的 ExponentialBackoffStrategy
中实现。
您可以通过创建一个实现了 Spatie\WebhookServer\BackoffStrategy\BackoffStrategy
的类来自定义回退策略。该接口看起来是这样的
namespace Spatie\WebhookServer\BackoffStrategy; interface BackoffStrategy { public function waitInSecondsAfterAttempt(int $attempt): int; }
您可以通过在 webhook-server
配置文件的 backoff_strategy
中指定其完全限定类名来使您自定义的策略成为默认策略。或者,您可以像这样为特定 webhook 指定策略。
WebhookCall::create() ->useBackoffStrategy(YourBackoffStrategy::class) ... ->dispatch();
在底层,webhook 调用的重试是通过使用 延迟分发 实现的。Amazon SQS 只支持较小的最大延迟。如果您使用 Amazon SQS 作为您的队列,请确保您没有以这种方式配置包,使得每次尝试之间有超过 15 分钟的时间。
自定义 HTTP 方法
默认情况下,所有 webhook 都将使用 post
方法。您可以通过在 webhook-server
配置文件的 http_verb
键中指定您想要的 HTTP 方法来自定义它。
您还可以使用 useHttpVerb
方法覆盖特定调用。
WebhookCall::create() ->useHttpVerb('get') ... ->dispatch();
添加额外头
您可以通过将额外的头部添加到 webhook-server
配置文件中的 headers
键来使用额外的头部。如果您想为特定的 webhook 添加额外的头部,可以使用 withHeaders
调用。
WebhookCall::create() ->withHeaders([ 'Another Header' => 'Value of Another Header' ]) ... ->dispatch();
使用代理
您可以通过在 webhook-server
配置文件中指定 proxy
键来通过代理直接路由 webhook。要为特定的请求设置代理,可以使用 useProxy
调用。
WebhookCall::create() ->useProxy('http://proxy.server:3128') ...
使用相互 TLS 认证
为了保护 webhook 数据传输的完整性,验证您 webhook 负载数据的预期接收者至关重要。相互 TLS 认证是这种目的的强大方法。与标准 TLS 不同,在标准 TLS 中只有客户端验证服务器,相互 TLS 要求 webhook 端点(作为客户端)和 webhook 提供者(作为服务器)相互验证。这是通过 TLS 握手期间交换证书来实现的,确保双方确认对方的身份。
注意:如果您需要包含自己的证书颁发机构,请将证书路径传递给
verifySsl()
方法。
WebhookCall::create() ->mutualTls( certPath: storage_path('path/to/cert.pem'), certPassphrase: 'optional_cert_passphrase', sslKeyPath: storage_path('path/to/key.pem'), sslKeyPassphrase: 'optional_key_passphrase' )
代理规范遵循 guzzlehttp 代理格式
验证接收应用的 SSL 证书
当使用以 https://
开头的 URL 时,该软件包将验证接收方的 SSL 证书是否有效。如果它无效,我们将认为 webhook 调用失败。我们不推荐这样做,但您可以通过将 webhook-server
配置文件中的 verify_ssl
键设置为 false
来关闭此验证。
您还可以使用 doNotVerifySsl
方法在每个 webhook 调用中禁用验证。
WebhookCall::create() ->doNotVerifySsl() ... ->dispatch();
添加元信息
您可以向 webhook 添加额外的元信息。这些元信息不会进行传输,它只会用于传递给 此软件包触发的事件。
这是添加元信息的方法
WebhookCall::create() ->meta($arrayWithMetaInformation) ... ->dispatch();
添加标签
如果您使用 Laravel Horizon 进行队列操作,您会很高兴地知道我们支持 标签。
要为执行 webhook 调用的底层作业添加标签,只需在 webhook-server
配置文件的 tags
键中指定它们或使用 withTags
方法。
WebhookCall::create() ->withTags($tags) ... ->dispatch();
异常处理
默认情况下,该软件包不会记录在发送 webhook 时抛出的任何异常。
要处理异常,您需要创建 Spatie\WebhookServer\Events\WebhookCallFailedEvent
和/或 Spatie\WebhookServer\Events\FinalWebhookCallFailedEvent
事件的监听器。
重试失败执行
默认情况下,失败的作业将被忽略。要在一项作业的最后尝试失败时抛出异常,可以调用 throwExceptionOnFailure
WebhookCall::create() ->throwExceptionOnFailure() ... ->dispatch();
或激活 webhook-server
配置文件的 throw_exception_on_failure
全局选项。
发送原始字符串主体而不是 JSON
默认情况下,所有 webhook 都会将有效负载转换为 JSON。您可以使用 sendRawBody(string $body)
选项发送任何字符串,而不是发送 JSON。
由于 Signer API 中的类型不匹配,目前不支持对原始数据请求进行签名。当使用 sendRawBody 选项时,您将在 WebhookEvents 中收到 string 有效负载。
WebhookCall::create() ->sendRawBody("<root>someXMLContent</root>") ->doNotSign() ... ->dispatch();
事件
该软件包会触发以下事件
DispatchingWebhookCallEvent
:在 webhook 调用将被派送到队列之前。WebhookCallSucceededEvent
:远程应用以2xx
响应代码响应。WebhookCallFailedEvent
:远程应用以非2xx
响应代码响应,或根本没有响应。FinalWebhookCallFailedEvent
:调用 webhook 的最后尝试失败。
所有这些事件都有以下属性
httpVerb
:用于执行请求的动词webhookUrl
:请求发送到的URLpayload
:使用的负载headers
:发送的头部信息。此数组包括签名头部meta
:使用meta
调用传递给webhook的值数组tags
:使用的标签数组uuid
:用于标识此调用的唯一字符串。此uuid将适用于webhook调用的所有尝试。
除了DispatchingWebhookCallEvent
之外,所有事件都有这些额外的属性
attempt
:尝试次数response
:远程应用返回的响应。可以是\GuzzleHttp\Psr7\Response
的实例或null
。
测试
composer test
测试Webhooks
当在自动化测试中使用该包时,您需要执行以下操作之一,以确保不会向真实网站发送webhook
总线
use Illuminate\Support\Facades\Bus; use Spatie\WebhookServer\CallWebhookJob; use Tests\TestCase; class TestFile extends TestCase { public function testJobIsDispatched() { Bus::fake(); ... Perform webhook call ... Bus::assertDispatched(CallWebhookJob::class); } }
队列
use Illuminate\Support\Facades\Queue; use Spatie\WebhookServer\CallWebhookJob; use Tests\TestCase; class TestFile extends TestCase { public function testJobIsQueued() { Queue::fake(); ... Perform webhook call ... Queue::assertPushed(CallWebhookJob::class); } }
更新日志
请参阅更新日志以获取有关最近更改的更多信息。
贡献
请参阅贡献指南以获取详细信息。
安全
如果您发现任何与安全相关的问题,请通过电子邮件freek@spatie.be联系我们,而不是使用问题跟踪器。
明信片软件
您可以自由使用此包,但如果它进入了您的生产环境,我们非常希望您能从您的家乡给我们寄一张明信片,说明您正在使用我们的哪个包。
我们的地址是:Spatie,Kruikstraat 22,2018 安特卫普,比利时。
我们将所有收到的明信片发布在我们的公司网站上。
鸣谢
许可证
MIT许可证(MIT)。请参阅许可证文件以获取更多信息。