Node.jsでWeb Push通知システムを自作する:Firebaseから卒業して軽量化を実現

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Web Pushはモバイルアプリだけのものではない

多くの開発者は、ブラウザにプッシュ通知(push notification)を送るにはFirebase Cloud Messaging (FCM)を使うのが当たり前だと思っています。しかし実際には、サードパーティに依存せず、インフラを完全にコントロールできるより「純粋な」解決策があります。それがW3C標準のWeb Pushプロトコルです。

以前、1日あたり約1,000件の注文を処理する物流管理ダッシュボードを担当したことがあります。当時、Firebase SDKを統合したことで、通知機能のためだけにフロントエンドのバンドルサイズが200KB近く増加しました。Node.jsweb-pushライブラリに切り替えた後、チームはこの負担を完全に排除できました。ページ読み込み速度が大幅に向上し、Google Consoleでの複雑なセットアップも不要になったため、デプロイプロセスも簡素化されました。

実装方法の比較

プッシュ通知を統合する際、主に2つのアプローチを検討することになります:

  • Firebase Cloud Messaging (FCM): Googleが仲介役となります。インフラはGoogleが担当しますが, 代わりに重いSDKを埋め込み、彼らの厳格なポリシーに従う必要があります。
  • Web Pushプロトコル (VAPID): これは直接的なアプローチです。VAPID(Voluntary Application Server Identification)キーペアを使用して、ChromeやFirefoxに組み込まれているPush Serviceに対してサーバーを認証します。

なぜ web-push はBackend Node.jsにおいて最適な選択なのか?

各ソリューションにはそれぞれの利点があります。しかし、軽量さとコントロール権を優先する場合、web-pushは非常に実用的なメリットをもたらします:

主なメリット:

  • 超軽量なバンドルサイズ: 巨大なSDKを埋め込む必要はありません。フロントエンドはイベントを待機するための数行の純粋なService Workerだけで済みます。
  • データセキュリティ: ユーザーの購読情報(subscription)は自前のデータベースに保存されます。あなたとブラウザ以外, 誰もその情報を知り得ません。
  • コスト削減: 完全に無料です。クォータ(制限)を超えたり、クラウドプロバイダーによる突然の価格改定を心配する必要はありません。
  • 自由なカスタマイズ: ペイロードの暗号化方法や通知の有効期限(TTL)を完全にコントロールできます。

注意点:

  • ユーザーのendpointkeysを保存するためのデータベーステーブルを自分で設計する必要があります。
  • 送信失敗時のリトライ(再試行)ロジックを実装する必要があります。

Web Pushの仕組み

スムーズに実装するために、データの流れを理解しましょう。データはサーバーからブラウザへ直接送られるのではなく、中継局を経由します:

  1. 購読 (Subscription): ブラウザがユーザーに権限を求めます。許可されると、Push Service(GoogleやMozillaが管理)のURLを含むsubscriptionオブジェクトを返します。
  2. 保存: フロントエンドはこのオブジェクトをNode.jsサーバーに送り、データベース(MongoDBやPostgreSQLなど)に保存します。
  3. プッシュ: 新しいイベントが発生すると、サーバーはweb-pushライブラリを使用してVAPIDキーで署名し、Push Serviceに送信します。Push Serviceは、ユーザーがウェブサイトを閉じていても通知を配信します。

詳細な実装ガイド

それではコードを書いていきましょう。Node.jsがインストールされたPCがあれば準備完了です。

ステップ1:プロジェクトの初期化とVAPIDキーの生成

まず、ディレクトリを作成し、必要なパッケージをインストールします:

mkdir web-push-tutorial
cd web-push-tutorial
npm init -y
npm install web-push express body-parser cors

VAPIDキーペアは、サーバーの電子署名のような役割を果たします。次のコマンドで素早く生成できます:

./node_modules/.bin/web-push generate-vapid-keys

Public KeyPrivate Key をコピーしておいてください。これらは次のステップで使用します。

ステップ2:Node.jsサーバーの構築

server.js ファイルを作成します。これが通知送信を制御する「脳」となります。

const webpush = require('web-push');
const express = require('express');
const app = express();

app.use(require('cors')());
app.use(require('body-parser').json());

const publicVapidKey = 'YOUR_PUBLIC_KEY';
const privateVapidKey = 'YOUR_PRIVATE_KEY';

webpush.setVapidDetails(
  'mailto:[email protected]',
  publicVapidKey,
  privateVapidKey
);

app.post('/subscribe', (req, res) => {
  const subscription = req.body;
  res.status(201).json({});

  const payload = JSON.stringify({
    title: 'システム通知',
    body: '注文 #1234 が確定されました!',
  });

  webpush.sendNotification(subscription, payload)
    .catch(err => console.error('プッシュ送信失敗:', err));
});

app.listen(5000, () => console.log('サーバーがポート5000で起動しました'));

ステップ3:クライアントとService Workerの設定

フロントエンドでは、client.js がブラウザへの登録を担当します。

const publicVapidKey = 'YOUR_PUBLIC_KEY';

async function subscribeUser() {
  // Service Workerを登録
  const register = await navigator.serviceWorker.register('/sw.js', { scope: '/' });

  // 購読(subscription)を作成
  const subscription = await register.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
  });

  // サーバーへ情報を送信
  await fetch('http://localhost:5000/subscribe', {
    method: 'POST',
    body: JSON.stringify(subscription),
    headers: { 'content-type': 'application/json' }
  });
}

最後は sw.js です。このファイルはバックグラウンドで動作し、通知ポップアップを表示します:

self.addEventListener('push', e => {
  const data = e.data.json();
  self.registration.showNotification(data.title, {
    body: data.body,
    icon: '/icon.png'
  });
});

エラーを避けるための実践的な経験

このシステムを本番環境(production)に導入する際、3つの重要なポイントに注意してください:

  • HTTPSが必須: ブラウザは、localhostを除き、HTTPで動作するサイトではService Workerを拒否します。
  • データベースのクリーンアップ: ユーザーが通知をブロックすると、Push Serviceは404または410エラーを返します。リソースの無駄を避けるため、その購読情報をすぐにデータベースから削除する必要があります。
  • ペイロードの制限: メッセージの最大サイズは4KBです。大量のデータやbase64画像をここに含めないようにしてください。

Web Pushシステムの自作は、思っているほど難しくありません。Googleのエコシステムに依存することなく、絶対的な柔軟性を提供し、アプリケーションをよりプロフェッショナルなものにします。ぜひ活用してみてください!

Share: