Laravel中FCM推送通知如何获取发送成功/失败的返回值
Laravel中FCM推送通知如何获取发送成功/失败的返回值
嘿,我来帮你搞定这个问题!你遇到的情况很常见——Laravel 默认的 notify() 方法本身是没有返回值的,所以你拿到的 $return 自然是空的。要获取FCM推送的成功/失败状态,得从你的通知类内部入手,捕获FCM的响应或者异常。下面给你两种可行的方案:
方案一:在通知类内直接捕获FCM响应
假设你用的是常用的 kreait/laravel-firebase 包(从你代码里的 FirebaseMessage 来看大概率是),可以修改你的 AlertNotification 类,手动调用FCM的发送方法并捕获响应:
use Kreait\Firebase\Messaging\CloudMessage; use Kreait\Firebase\Messaging\Messaging; use Kreait\Firebase\Exception\MessagingException; use Kreait\Firebase\Exception\Messaging\InvalidRegistrationToken; use Kreait\Firebase\Exception\Messaging\DeviceNotRegistered; use Illuminate\Notifications\Notification; class AlertNotification extends Notification { protected $payload; protected $fcmResponse; // 存储FCM推送的响应结果 public function __construct($payload) { $this->payload = $payload; } public function via($notifiable) { return ['firebase']; } public function toFirebase($notifiable) { $messaging = app(Messaging::class); // 获取FCM实例 try { // 构造FCM消息 $message = CloudMessage::withTarget('token', $this->payload['token']) ->withData([ 'title' => $this->payload['title'], 'body' => $this->payload['body'], 'url' => $this->payload['url'], 'method' => $this->payload['method'], 'sound' => $this->payload['sound'] // 补充你需要的其他data字段 ]); // 发送消息并获取响应 $this->fcmResponse = $messaging->send($message); return $this->fcmResponse; } catch (InvalidRegistrationToken $e) { // 无效的FCM令牌,标记用户token为无效 $notifiable->update(['fcm_token' => null]); $this->fcmResponse = [ 'success' => false, 'error' => '无效的FCM令牌', 'code' => $e->getCode() ]; } catch (DeviceNotRegistered $e) { // 设备未注册,同样标记token无效 $notifiable->update(['fcm_token' => null]); $this->fcmResponse = [ 'success' => false, 'error' => '设备未注册', 'code' => $e->getCode() ]; } catch (MessagingException $e) { // 其他推送异常 $this->fcmResponse = [ 'success' => false, 'error' => $e->getMessage(), 'code' => $e->getCode() ]; } return $this->fcmResponse; } // 新增方法,让控制器可以获取推送结果 public function getFcmResponse() { return $this->fcmResponse; } }
然后在你的控制器里,这样获取结果:
$notification = new AlertNotification([ 'title' => $data['title'], 'body' => $data['body'], 'url' => $data['url'], 'method' => $data['method'], 'token' => $token, 'sound' => $sound ]); // 发送通知 $user->notify($notification); // 获取推送结果 $return = $notification->getFcmResponse(); // 根据结果处理业务逻辑 if (isset($return['success']) && !$return['success']) { // 推送失败,比如记录日志 \Illuminate\Support\Facades\Log::error('FCM推送失败: ' . $return['error']); } else { // 推送成功,FCM返回的响应里会有message_id等信息 \Illuminate\Support\Facades\Log::info('FCM推送成功,消息ID: ' . $return->messageId()); }
方案二:监听Laravel的通知发送事件
如果你不想修改通知类的核心逻辑,可以通过监听Laravel内置的 NotificationSent 事件来捕获推送响应:
- 首先在
app/Providers/EventServiceProvider.php里注册事件监听器:
protected $listen = [ \Illuminate\Notifications\Events\NotificationSent::class => [ \App\Listeners\LogFcmNotificationResponse::class, ], ];
- 创建对应的监听器
app/Listeners/LogFcmNotificationResponse.php:
namespace App\Listeners; use Illuminate\Notifications\Events\NotificationSent; use Illuminate\Support\Facades\Log; class LogFcmNotificationResponse { public function handle(NotificationSent $event) { // 只处理我们的AlertNotification if ($event->notification instanceof \App\Notifications\AlertNotification) { $response = $event->response; // 判断推送状态 if (is_object($response) && method_exists($response, 'messageId')) { Log::info('FCM推送成功,消息ID: ' . $response->messageId()); } elseif (isset($response['success']) && !$response['success']) { Log::error('FCM推送失败: ' . $response['error']); } } } }
这个方案的前提是你的通知类的 toFirebase 方法已经返回了FCM的响应(也就是方案一中的返回逻辑),这样 NotificationSent 事件里的 $event->response 才会有值。
关键注意点
- 不同的FCM异常对应不同的失败场景,比如无效token、设备未注册,这些都需要针对性处理(比如标记用户的FCM token为无效,避免后续重复推送浪费资源)
- 如果你用的是其他FCM相关包,核心逻辑是一样的:找到发送消息的底层方法,捕获它的响应或异常,再传递给控制器或事件处理
备注:内容来源于stack exchange,提问作者user1666858
相关产品推荐
相关产品推荐

