那时候找不到完全符合需求的可以直接用或改,所以最後自己写了一个,供大家参考。
根据我爬文,要用 Laravel 实作 Webhook 的方法应该不只一种,也有已经写好的套件可以使用,可以花点时间看,再根据自己需求选择用做好的或自开发。
本次只会分享「发送通知」和「触发发送通知」的写法
实作上会用到这两样,我的理解如下
又因为需要控制送到哪、与是否启用,新增 subscribes table,去记录。
schema 设计如下,一个分销商(client)可以订阅多个事件(event),每个订阅可以设置一个endpoint(url)、且可以控制是否启用(active)
Subscribes |
---|
id |
event_name |
client_id |
active |
url |
created_at |
updated_at |
<?php
namespace App\Notifications;
use App\Channels\WebhookChannel;
use App\Models\Subscribe;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class WebhookNotification extends Notification implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public $tries = 10; // 可以设定最多重试几次
public $timeout = 45; // 等待分销商几秒後没有回覆算失败
public $retryAfter = 100; // 若失败後几秒重试
/**
* Where the webhook notification will send to
*
* @var string
*/
public $url;
/**
* Webhook event
*
* @var string
*/
public $event;
/**
* Gds Client instance
*
* @var App\Models\Client
*/
public $client;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct(Subscribe $subscribe)
{
$this->url = $subscribe->url;
$this->event = $subscribe->event;
$this->client = $subscribe->client;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return [WebhookChannel::class];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
*/
public function toWebhook($notifiable)
{
// 根据不同事件组讯息
switch ($this->event) {
case 'product_status_updated':
return [
'event' => $this->event,
'product_id' => $notifiable->prod_id,
'product_name' => $notifiable->prod_name,
'new_status' => $notifiable->prod_status,
// 时间资讯会想送「寄送」时间,所以在 Channel 再做
];
case 'order_status_updated':
return [
'event' => $this->event,
'order_id' => $notifiable->order_id,
'order_voucher' => $notifiable->order_voucher,
'new_status' => $notifiable->order_status,
// 时间资讯会想送「寄送」时间,所以在 Channel 再做
];
// ...之後有新事件可以加在下面
}
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
<?php
namespace App\Channels;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Illuminate\Notifications\Notifiable;
use Illuminate\Notifications\Notification;
class WebhookChannel
{
public function __construct()
{
$this->client = new Client();
}
/**
* @param Notifiable $notifiable
* @param Notification $notification
* @throws WebHookFailedException
*/
public function send($notifiable, Notification $notification)
{
if (method_exists($notification, 'toWebhook')) {
$body = (array) $notification->toWebhook($notifiable);
} else {
$body = $notification->toArray($notifiable);
}
// 放时间资讯
$timestamp = now();
$body['timestamp'] = $timestamp->format('Y-m-d H:i:s');
$headers = [
'Content-Type' => 'application/json'
];
$url = $notification->url;
$request = new Request('POST', $url, $headers, json_encode($body));
try {
$response = $this->client->send(
$request,
['timeout' => 45.0]
);
// 这边看你觉得定义收到什麽回覆算成功,
// 可以是收到 code 2XX、200、或特定讯息
// 以下范例是只有收到 200 系统才是为成功
if ($response->getStatusCode() == 200) {
// Success
} else {
// Get a non 200 respones
$notification->release(100); // 100秒後重新再跑一次
}
} catch (Throwable $th) {
// handle exception
}
}
}
以产品状态异动为例,可以利用 model 在 saving 的时候触发发送
class Product extends Model
{
use Notifiable; // 要加这个
protected static function boot()
{
parent::boot();
// 在储存时触发
static::saving(function ($product) {
// 检查状态是否有异动
$prev_status = $product->getOriginal('prod_status');
if ($prev_status != $product->prod_status) {
// 对有该产品下所有的订阅发送通知
$subscribes = $product->getSubscribes("product_status_updated");
foreach ($subscribes as $subscribe) {
$product->notify(new WebhookNotification($subscribe));
}
}
});
}
public function getSubscribes($event)
{
return Subscribe::where('active', 1)
->where('event_name', $event)
->get();
}
}
>>: Day09 - 用 Cloud Run 部属 Serverless 容器应用
前言 从今天以及之後的几篇文章,将介绍如何打造 GitLab CI 流水线,以及如何透过 ArgoC...
身为一个第一线协助客户处理Microsoft 365大大小小的技术人员 如果遇到M365茶包射击(T...
透过昨天的范例我们知道要绑定HTML属性需要使用v-bind指令,而今天我们要介绍的是v-bind绑...
嘿不知不觉的就来到倒数第二篇了呢!网页也写完了呢!是不是要发布了哇! 今天就来说说 Github p...
今天要来解APCS的题目,这次是105年10月29的实作题第二题,那我们就开始吧! 题目 解答 a=...