Laravel自定义通知渠道:如何捕获外部API调用响应?
解决Laravel按需通知捕获API响应的问题
针对你遇到的AnonymousNotifiable下notify()无返回值、无法直接获取渠道API响应的问题,这里提供两个直接可行的方案,不需要依赖缓存或事件:
方案一:扩展AnonymousNotifiable类,捕获发送结果
Laravel默认的AnonymousNotifiable的notify()方法是无返回值的,我们可以自定义一个可追踪的版本,让它收集每个渠道的发送结果并返回:
1. 创建自定义可追踪通知类
namespace App\Notifications; use Illuminate\Notifications\AnonymousNotifiable; use Illuminate\Notifications\Events\NotificationSent; class TrackableAnonymousNotifiable extends AnonymousNotifiable { protected $sendResults = []; public function notify($notification) { foreach ($this->routes as $channel => $route) { $channelClass = $this->channel($channel); $method = 'to' . class_basename($channel); if (method_exists($notification, $method)) { $message = $notification->{$method}($this); // 调用渠道发送方法并捕获返回结果 $result = $channelClass->send($this, $message); $this->sendResults[$channel] = $result; // 保持原有事件触发逻辑(可选,不影响核心功能) event(new NotificationSent($this, $notification, $channel, $result)); } else { $this->sendResults[$channel] = [ 'status' => 'failed', 'reason' => 'Notification class does not support this channel' ]; } } return $this->sendResults; } // 可选:提供获取结果的额外方法 public function getSendResults() { return $this->sendResults; } }
2. 修改调用逻辑使用自定义类
替换原有的Notification::route()调用,改用我们的自定义类:
$notification = new SendVerificationCode([ "otp" => $otp, ]); $trackableNotifiable = new \App\Notifications\TrackableAnonymousNotifiable(); // 直接获取各渠道的发送结果 $sendResults = $trackableNotifiable ->route('mail', $emailAddress) ->route('mobile_number', $phoneNumber) ->notify($notification); // 示例:处理结果 if ($sendResults['mail']['status'] === 'success') { // 邮件发送成功逻辑 } else { // 邮件发送失败,返回错误信息给用户 } if ($sendResults['mobile_number']['code'] === 200) { // 短信发送成功逻辑 }
方案二:确保自定义渠道返回API响应
上面的方案能生效的前提是你的自定义渠道send()方法会返回API响应结果。如果之前的渠道方法是无返回值的,需要修改它们:
自定义邮件渠道示例
namespace App\Channels; use Illuminate\Notifications\Notification; class MailChannel { public function send($notifiable, Notification $notification) { $message = $notification->toMail($notifiable); // 调用外部邮件API并获取响应 $apiResponse = $this->callExternalMailApi($message); // 返回API响应结果 return $apiResponse; } protected function callExternalMailApi($message) { // 实际调用逻辑,比如用Guzzle请求API $client = new \GuzzleHttp\Client(); $response = $client->post('https://your-mail-provider/api/send', [ 'json' => [ 'to' => $message->to[0]['address'], 'content' => $message->content ] ]); return json_decode($response->getBody(), true); } }
自定义短信渠道示例
namespace App\Channels; use Illuminate\Notifications\Notification; class SmsChannel { public function send($notifiable, Notification $notification) { $message = $notification->toSms($notifiable); // 调用外部短信API并获取响应 $apiResponse = $this->callExternalSmsApi($message); // 返回API响应结果 return $apiResponse; } protected function callExternalSmsApi($message) { $client = new \GuzzleHttp\Client(); $response = $client->post('https://your-sms-provider/api/send', [ 'form_params' => [ 'phone' => $notifiable->routeNotificationFor('mobile_number'), 'text' => $message->content ] ]); return json_decode($response->getBody(), true); } }
关键说明
- 方案一的核心是绕过默认的
Notification::route(),用自定义类实现有返回值的通知发送逻辑,完全适配OTP场景下即时获取发送状态的需求。 - 两个方案配合使用,既能捕获每个渠道的API响应,又不需要依赖缓存、会话或事件监听,属于原生逻辑的扩展,没有临时方案的弊端。
内容的提问来源于stack exchange,提问作者UnderIdentityCrisis
相关产品推荐
相关产品推荐

