via()返回值错误会导致通知静默失败,必须返回已注册渠道名的字符串数组(如['mail','database']);数据库需加notifiable_id+notifiable_type联合索引;广播通知要确保频道类型、鉴权和前端订阅严格匹配。

via() 返回值写错,通知就完全不发
这是最常踩的坑:通知类里 via() 方法返回空数组、拼错渠道名(比如 'mails')、或写了未安装的渠道(比如 'vonage' 但没装包也没配 config/services.php),Laravel 就直接跳过发送,连日志都不打——静默失败。
必须确保它返回一个字符串数组,且每个元素是 Laravel 已注册的合法渠道名:
-
['mail']→ 发邮件(需配置MAIL_MAILER) -
['database']→ 存进notifications表(需先跑php artisan notifications:table和migrate) -
['mail', 'database']→ 同时发邮件并存库 -
['broadcast']→ 推送到广播频道(需BROADCAST_DRIVER配好,且前端用 Laravel Echo 订阅对应频道)
数据库通知查得慢?缺联合索引是主因
用 database 渠道后,$user->unreadNotifications 或分页拉取时卡顿,大概率是 notifications 表缺索引。Laravel 默认建表只加了 id 主键,没加查询必需的联合索引。
手动补上这组索引能立竿见影:
-
notifiable_id+notifiable_type联合索引(核心,用于按用户查通知) -
notifiable_id+notifiable_type+read_at复合索引(优化未读筛选)
执行迁移时可直接在 create_notifications_table 的 Schema 中加上:$table->index(['notifiable_id', 'notifiable_type'])。
广播通知收不到?频道类型和鉴权必须咬死
前端调 echo.private('user.123') 却收不到,90% 是后端频道类型、路由授权、前端订阅三者没对齐。
检查这几点:
- 通知类中
broadcastOn()返回的是new PrivateChannel('user.' . $notifiable->id),那routes/channels.php必须有对应授权逻辑,例如:Broadcast::channel('user.{id}', function ($user, $id) { return (int) $user->id === (int) $id; }); - 前端订阅方法必须是
private()(不是channel()),且频道名大小写、数字类型(整数123vs 字符串'123')要完全一致 -
BROADCAST_DRIVER=redis时,php artisan queue:work必须在运行——Redis 广播靠队列进程把事件推到 Redis,不是直连
构造函数传模型,小心序列化爆炸和 N+1
别在通知构造函数里直接塞 $order 模型实例,然后在 toMail() 里写 $this->order->user->name。这会导致两个问题:
- 队列中执行时触发延迟加载,一次通知可能查出十几张表(N+1)
- 模型序列化进 Redis 或广播 payload 时,会把关联关系、属性访问器、甚至整个容器都拖进去,payload 超限或失败
正确做法是只传必要字段:
- 构造函数收
$orderId和$userId这类标量值 - 在
toMail()、toDatabase()等方法里按需查数据,用Order::with('user')->find($this->orderId)控制加载范围 - 如果只是展示简单信息,直接在构造时取好字段:
$this->orderName = $order->name,避免后续任何动态访问
复杂通知逻辑一旦涉及模型关系,就得主动切开数据流——传 ID,查数据,格式化,丢掉原始模型实例。











