You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 事件来捕获推送响应:

  1. 首先在 app/Providers/EventServiceProvider.php 里注册事件监听器:
protected $listen = [
    \Illuminate\Notifications\Events\NotificationSent::class => [
        \App\Listeners\LogFcmNotificationResponse::class,
    ],
];
  1. 创建对应的监听器 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 08:48:09