You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular推送通知重复接收问题:重复生成Push Subscription

解决Angular推送订阅重复存储问题

客户端:优先使用已有订阅

每次页面加载直接请求新订阅是问题根源,先检查浏览器是否已有有效订阅,再决定是否发起新请求:

export class AppModule {
  constructor(update: SwUpdate, push: SwPush, pushToServer: SubscribeNotificationService) {
    if (push.isEnabled) {
      // 监听现有订阅状态
      push.subscription.subscribe(existingSub => {
        if (existingSub) {
          // 已有订阅,提交到服务器(可加服务器校验步骤)
          console.log("使用已有订阅提交");
          pushToServer.addPushSubscriber(existingSub).then(res => 
            console.log("提交结果: " + res)
          );
        } else {
          // 无订阅时发起请求
          push.requestSubscription({
            serverPublicKey: environment.VAPID_PUBLIC_KEY
          })
          .then(newSub => {
            console.log("新订阅生成:", newSub.toJSON());
            pushToServer.addPushSubscriber(newSub).then(res => 
              console.log("新订阅提交结果: " + res)
            );
          })
          .catch(err => console.error("订阅请求失败:", err));
        }
      });
    }
  }
}

服务器端:基于Endpoint去重

客户端逻辑只能减少重复请求,服务器端必须做最终校验:

  • 以订阅对象的endpoint字段作为唯一标识(每个订阅对应唯一的推送地址)
  • 收到订阅请求时,先查询数据库是否存在相同endpoint的记录
  • 存在则更新记录(如关联用户、过期时间),不存在则新增

服务层优化(可选)

可以在服务中增加前置校验,减少无效请求:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environments';

@Injectable({
  providedIn: 'root'
})
export class SubscribeNotificationService {

  readonly VAPID_PUBLIC_KEY = environment.VAPID_PUBLIC_KEY;

  constructor(private http: HttpClient) { }

  addPushSubscriber(subscription: any) {
    return new Promise((resolve, reject) => {
      // 直接提交,由服务器处理去重逻辑
      this.http.post(environment.PUSHNOTIFICATION_API, subscription)
        .subscribe({
          next: resolve,
          error: reject
        });
    });
  }

  // 可选:新增校验接口,检查服务器是否已有该订阅
  checkSubscriptionExists(endpoint: string) {
    return this.http.get(`${environment.PUSHNOTIFICATION_API}/check?endpoint=${endpoint}`);
  }
}

核心要点

  • SwPush.subscription会返回浏览器保存的有效订阅,无需每次重新请求
  • 浏览器自动维护订阅生命周期,失效时subscription会返回null,此时才需要重新订阅
  • 服务器端的去重是避免重复通知的关键,确保同一客户端只有一条有效订阅记录

内容的提问来源于stack exchange,提问作者user17293718

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:06:40