向Mozilla推送通知的正确cURL请求格式及错误排查
解决Mozilla推送通知端点请求的cURL格式问题
问题背景
尝试向Mozilla推送通知端点发送请求时,先后遇到两个错误:
- 初始代码返回HTTP 400(错误请求)
- 调整后代码返回HTTP 401(未授权),提示
Missing VAPID token
第一段错误代码(HTTP 400)
$subscription = [ 'endpoint' => 'https://updates.push.services.mozilla.com/wpush/v2/gAAAAABmzIip-iAcvn_g_o6eozX5RHOx-sHSKwWC8jDlupllbqSp0Rx79PvC98rR8RDBlEnYJNwBbdfT8Y6sNbguUELQJN004HS6Zlei3liawWeOvuvrOZ3iFas454yVz2309sjo0AambY_xDwbT3_DMksEYEYfalg2_0qsclERpI3vxUhekULw', 'keys' => [ 'p256dh' => 'BEfhmTqDfYiuz9X708IQp3EF04JjFYEa8NZ2sG8K1m7mXxjNorfpHBBcmlS26jYC3Tz0BA7gp1mE........', 'auth' => 'SArepOvQdGABbEq1N.....', ] ]; $payload = json_encode([ 'title' => 'New Notification', 'body' => 'This is a test notification from Web Site Maker', ]); $headers = [ 'Content-Type: application/json', 'TTL: 60', $subscription // 错误:直接将数组放入headers,导致请求格式无效 ]; $options = [ CURLOPT_HTTPHEADER => $headers, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => true, ]; $ch = curl_init($endpoint); curl_setopt_array($ch, $options); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { echo "Error: $error"; } else { if ($httpCode != 201) { echo "Notification failed with HTTP code: $httpCode"; } else { echo "Notification sent successfully! Payload: $payload"; } }
错误原因:
- 将
$subscription数组直接放入HTTP headers,headers只能是字符串键值对,直接导致请求格式错误。 - 未对payload进行加密,Mozilla推送服务要求payload必须用用户订阅的公钥加密后发送。
- 缺少VAPID授权信息。
第二段错误代码(HTTP 401)
$headers = [ 'Content-Type: application/json', 'TTL: 86400', 'Topic: new_mail', 'Authorization: '.$publicVapidKey // 错误:VAPID授权格式不正确 ]; $options = [ CURLOPT_URL => $endpoint, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => $headers, ]; $ch = curl_init(); curl_setopt_array($ch, $options); $response = curl_exec($ch);
错误返回:
{"code":401,"errno":109,"error":"Unauthorized","message":"Missing VAPID token","more_info":"http://autopush.readthedocs.io/en/latest/http.html#error-codes"}
错误原因:
- VAPID授权头格式错误:正确格式应为
Authorization: Bearer <JWT_TOKEN>,直接使用公钥无法通过验证。 - 仍未处理payload加密。
解决方案
Web Push涉及复杂的加密和VAPID签名,推荐使用成熟的PHP库简化实现,比如minishlink/web-push。
步骤1:安装依赖
composer require minishlink/web-push
步骤2:完整实现代码
require __DIR__ . '/vendor/autoload.php'; use Minishlink\WebPush\WebPush; use Minishlink\WebPush\Subscription; // 你的VAPID密钥(需要提前生成) $vapidKeys = [ 'publicKey' => '你的VAPID公钥', 'privateKey' => '你的VAPID私钥', ]; // 用户的订阅信息 $subscription = Subscription::create([ 'endpoint' => 'https://updates.push.services.mozilla.com/wpush/v2/gAAAAABmzIip-iAcvn_g_o6eozX5RHOx-sHSKwWC8jDlupllbqSp0Rx79PvC98rR8RDBlEnYJNwBbdfT8Y6sNbguUELQJN004HS6Zlei3liawWeOvuvrOZ3iFas454yVz2309sjo0AambY_xDwbT3_DMksEYEYfalg2_0qsclERpI3vxUhekULw', 'keys' => [ 'p256dh' => 'BEfhmTqDfYiuz9X708IQp3EF04JjFYEa8NZ2sG8K1m7mXxjNorfpHBBcmlS26jYC3Tz0BA7gp1mE........', 'auth' => 'SArepOvQdGABbEq1N.....', ] ]); // 通知内容 $payload = json_encode([ 'title' => 'New Notification', 'body' => 'This is a test notification from Web Site Maker', ]); // 初始化WebPush客户端 $webPush = new WebPush($vapidKeys); // 发送通知 $webPush->sendOneNotification( $subscription, $payload ); // 处理响应 foreach ($webPush->flush() as $report) { $endpoint = $report->getEndpoint(); if ($report->isSuccess()) { echo "通知成功发送到 {$endpoint}"; } else { echo "通知发送到 {$endpoint} 失败: {$report->getReason()}"; } }
关键注意点
- VAPID密钥生成:使用以下命令生成VAPID密钥对(需安装web-push工具):
web-push generate-vapid-keys - 订阅信息验证:确保用户的
p256dh和auth密钥完整且正确,不能省略部分字符。 - 加密处理:库会自动处理payload的加密,无需手动实现Web Push加密标准。
- 授权头格式:库会自动生成正确的
Authorization和Crypto-Key头,无需手动拼接。
内容的提问来源于stack exchange,提问作者Europeuser
相关产品推荐
相关产品推荐

