在PHP web应用中通过JS向指定用户发送web push通知的方案咨询
定向Web推送通知实现方案
核心实现逻辑
你现有已实现的静态推送是全量给所有订阅用户发送,要实现按device_id定向发送,只需要新增「用户标识-推送订阅」的关联存储逻辑,不需要重构现有推送的核心展示逻辑:
- 用户授权推送权限时,同步采集当前用户的device_id、登录态中的用户ID,和推送库返回的订阅对象(包含endpoint、授权密钥等Web Push必填参数)一起提交到后端
- 在你现有的MySQL库中新增推送订阅关联表,存储字段建议为:自增主键、user_id(登录用户ID)、device_id(设备标识)、push_subscription(JSON类型存储完整订阅对象)、is_valid(布尔类型标记订阅是否有效)、create_time
- 需要发定向告警时,先按照目标device_id或者用户ID从MySQL查询所有有效的订阅记录,遍历调用你现有推送库的发送接口给对应订阅发通知即可
关键代码示例
前端订阅关联逻辑
// 推送授权逻辑,和你现有逻辑兼容 if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.ready.then(async reg => { // 获取推送订阅对象,和你现有实现一致 const subscription = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: '你的VAPID公钥' }) // 采集/生成device_id,存在本地避免重复生成 let deviceId = localStorage.getItem('custom_device_id') if (!deviceId) { // 自定义生成唯一device_id的逻辑,可按需求调整 deviceId = Math.random().toString(36).substring(2) + Date.now().toString(36) localStorage.setItem('custom_device_id', deviceId) } // 提交关联数据到后端存储 fetch('/api/bind-push-subscription', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ user_id: window.currentLoginUserId, // 从你现有登录逻辑中取当前登录用户ID device_id: deviceId, subscription: subscription }) }) }) }
后端定向推送触发逻辑(Node.js示例)
const webpush = require('web-push') const mysql = require('mysql2/promise') // 配置VAPID密钥,和你现有推送配置一致 webpush.setVapidDetails( 'mailto:你的运维联系邮箱', '你的VAPID公钥', '你的VAPID私钥' ) /** * 定向推送函数 * @param {Object} filter 筛选条件,支持按device_id或user_id筛选 * @param {Object} payload 推送内容,包含标题、正文、跳转链接等 */ async function sendTargetedNotification(filter, payload) { const conn = await mysql.createConnection({ host: '你的MySQL地址', user: '数据库用户名', password: '数据库密码', database: '你的业务库名' }) // 构建查询条件 let querySql = 'SELECT id, push_subscription FROM push_subscriptions WHERE is_valid = 1' const queryParams = [] if (filter.device_id) { querySql += ' AND device_id = ?' queryParams.push(filter.device_id) } if (filter.user_id) { querySql += ' AND user_id = ?' queryParams.push(filter.user_id) } const [rows] = await conn.execute(querySql, queryParams) // 遍历发送推送 for (const row of rows) { const subscription = JSON.parse(row.push_subscription) try { await webpush.sendNotification(subscription, JSON.stringify(payload)) } catch (err) { // 发送失败说明订阅已失效,标记为无效避免后续重复发送 await conn.execute('UPDATE push_subscriptions SET is_valid = 0 WHERE id = ?', [row.id]) } } await conn.end() } // 调用示例:给指定device_id的用户发送告警 sendTargetedNotification( {device_id: '目标用户的device_id'}, { title: '系统告警', body: '你负责的业务模块出现异常,请及时处理', data: {jumpUrl: '/alarm/detail?id=xxx'} } )
注意事项
- 若需要支持跨设备推送,同一个用户登录不同设备时会生成不同的device_id,存储多条订阅记录,按user_id筛选时会给该用户所有设备发送通知
- 推送发送失败时及时清理无效订阅,避免产生不必要的资源消耗
- 你现有Service Worker中监听
push事件展示通知的逻辑无需修改,和现有推送实现完全兼容
内容的提问来源于stack exchange,提问作者Aayush Gupta
相关产品推荐
相关产品推荐

