如何使用Laravel向桌面端特定用户发送推送通知?
桌面端特定用户推送通知实现方案
你当前遇到页面重载就触发通知的核心原因:Push.create 通知触发逻辑直接写在页面全局加载流中,没有做「当前用户是否为通知接收人」「是否存在未读新通知」的前置判断,只要页面刷新代码就执行,自然会出现误触发。
具体实现按以下步骤改造即可:
一、后端逻辑改造
1. 优化现有通知存储逻辑
你当前的store方法存在重复查询数据库的问题,循环内重复查询用户信息完全可以复用已有查询结果,优化后代码如下:
public function store(Request $request) { // 一次性查询目标用户,避免循环内重复查库 $targetUsers = User::where('user_type',1)->where('status',1)->get(['id','email']); foreach($targetUsers as $user){ $userNotification = new UserNotification(); $userNotification->user_id = $user->id; $userNotification->notification_id = $notification->id; $userNotification->is_read = 0; // 补充已读状态字段,默认未读 $userNotification->save(); $details = ['email' => $user->email]; $emailJob = (new UserNotificationMailJob($details))->delay(Carbon::now()->addMinutes(1)); dispatch($emailJob); } Session::flash('message','Notification is SuccessFully Sent'); return redirect()->back(); }
2. 新增当前用户未读通知查询接口
新增接口专门返回当前登录用户本人的未读新通知,加时间过滤避免历史未读通知每次刷新都重复弹出,示例代码:
// 通知控制器内新增方法,配置对应路由即可 public function getMyUnreadNotifications() { $currentUser = auth()->user(); // 只查询当前用户最近30分钟内的未读通知,可根据业务调整时间范围 $unreadList = UserNotification::with('notification') ->where('user_id', $currentUser->id) ->where('is_read', 0) ->where('created_at', '>', now()->subMinutes(30)) ->get(); return response()->json([ 'code' => 0, 'data' => $unreadList ]); }
3. 新增通知标记已读接口
通知被用户点击/展示后标记为已读,避免重复推送,示例逻辑:
public function markNotificationRead($id) { UserNotification::where('id', $id) ->where('user_id', auth()->id()) ->update(['is_read' => 1]); return response()->json(['code' => 0]); }
二、前端逻辑改造
1. 移除全局直接触发的通知代码
把原来直接写在页面加载逻辑里的裸Push.create代码全部删掉,从根源解决刷新就弹的问题。
2. 增加前置判断再触发通知
页面加载后先校验通知权限,再拉取当前用户本人的未读通知,只有存在有效未读通知时才触发弹窗,示例代码:
document.addEventListener('DOMContentLoaded', function() { // 先检查浏览器通知权限,无权限时先申请权限 if (!Push.Permission.has()) { Push.Permission.request(); return; } // 拉取当前登录用户的未读通知,接口地址替换为你自己的路由 fetch('/notification/my-unread', { method: 'GET', credentials: 'same-origin' // 自动携带登录态cookie }) .then(res => res.json()) .then(res => { if (res.code !== 0 || !res.data.length) return; // 遍历未读通知逐个弹出 res.data.forEach(notifyItem => { Push.create(notifyItem.notification.title || 'Work From Here', { body: notifyItem.notification.content || "You have new Notification!", timeout: 5000, icon: iconPath, onClick: function() { // 点击通知跳转到对应业务页面 window.location.href = notifyItem.notification.target_url || '/'; this.close(); // 标记通知已读,避免下次刷新重复弹 fetch(`/notification/read/${notifyItem.id}`, { method: 'POST', credentials: 'same-origin' }); } }); }) }) })
三、实时推送优化(可选)
如果需要实现「后端发通知后用户无需刷新页面立刻收到」的效果,可以用WebSocket私有频道方案:后端发通知时向对应用户的私有频道推送事件,前端登录后监听自己的私有频道,收到事件后再触发Push.create即可,这种方案精准度更高,完全不会出现给非目标用户弹通知的问题。

内容的提问来源于stack exchange,提问作者zubair syslab
相关产品推荐
相关产品推荐

