php怎么实现浏览器通知_php后端触发Web Push推送【通知】

8次阅读

web push通知不能由php直接发送给浏览器,php仅负责存储endpoint、加密payload并调用fcm/webpush api;需用web-push-php库处理vapid签名与aes-gcm加密,避免手写加密逻辑,并严格校验响应以清理失效endpoint。

php怎么实现浏览器通知_php后端触发Web Push推送【通知】

Web Push 通知不能靠 PHP 直接发给浏览器

PHP 本身没有能力直接向用户浏览器发送 Web Push 通知——它既不持有推送端点(endpoint),也不管理用户授权状态,更无法加密消息并调用 https://fcm.googleapis.com/v1/projects/... 这类推送服务接口。真正触发通知的是前端注册的 ServiceWorker后端(PHP)只负责把加密后的消息 POST 到推送服务(如 Firebase Cloud Messaging 或 WebPush 服务)。

PHP 要做的三件事:存 endpoint、加密 payload、调用 FCM / WebPush API

用户在前端点击“允许通知”后,registration.pushManager.subscribe() 返回一个 PushSubscription 对象,其中的 endpointkeys.p256dhkeys.auth 必须由 PHP 安全存储(比如数据库),后续推送时才能复用。

  • curl_init()https://fcm.googleapis.com/v1/projects/YOUR-PROJECT-ID/messages:send 发送 POST 请求(需 OAuth2 Token
  • 或使用标准 WebPush 协议(推荐):用 web-push-php 库(如 minishlink/web-push),它自动处理 VAPID 签名、AES-GCM 加密、HTTP/2 头设置
  • 不要手写加密逻辑——libsodiumsodium_crypto_aead_aes256gcm_encrypt() 参数顺序、nonce 长度、padding 方式极易出错
  • PHP 7.2+ 必须启用 sodium 扩展;若用 minishlink/web-push,还要确保 cURL 支持 HTTP/2(curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0)

常见错误:401 Unauthorized、410 Gone、400 Bad Request

这些不是 PHP 写错了,而是推送链路中某环断了:

  • 401 Unauthorized:VAPID 公钥没配到前端 subscribe()applicationServerKey,或私钥签名时用了错误的 aud(应为推送服务域名,如 https://fcm.googleapis.com
  • 410 Gone:前端返回的 endpoint 已失效(用户清除站点数据、禁用通知、换设备),PHP 必须捕获该响应并从数据库删掉这条记录
  • 400 Bad Request:payload 超过 4KB(含加密开销)、ttl 设为负数、或 contentEncoding 头没设成 aes128gcm
  • 别忽略 Content-Encoding: aes128gcmEncryptionCrypto-Key 这三个 header——minishlink/web-push 会自动生成,手动发请求时漏一个就 400

简单示例:用 web-push-php 发一条通知

安装:composer require minishlink/web-push

立即学习PHP免费学习笔记(深入)”;

use MinishlinkWebPushWebPush; use MinishlinkWebPushSubscription;  $auth = [     'VAPID' => [         'subject' => 'mailto:admin@example.com',         'publicKey' => 'BEm...xxx', // base64url 编码         'privateKey' => 'oFm...xxx',     ], ];  $webPush = new WebPush($auth);  // 从数据库查出用户的 subscription 数据 $subscription = Subscription::create([     'endpoint' => 'https://fcm.googleapis.com/fcm/send/xxx',     'publicKey' => 'xxx',     'authToken' => 'xxx', ]);  $webPush->sendOneNotification($subscription, '{"title":"Hi","body":"From PHP"}');

注意:sendOneNotification() 返回的是 Response 对象,必须检查 $response->isSuccess()$response->getReasonPhrase(),否则失败静默,你根本不知道通知没发出去。

VAPID 私钥绝对不能硬编码在 PHP 文件里,也不能进 git;endpoint 和 keys 存数据库时建议加密(如用 openssl_encrypt + 主密钥)。推送不是发邮件,一次失败就得清理脏数据,不然下次还试。

text=ZqhQzanResources