Web Pushを試してみた(バックエンド編)

2024.03.26.火
技術

こんにちは、入社2年目の茶谷です。

今回は、「Web Pushを試してみた(フロントエンド編)」の続きとして、バックエンドを実装していきます!

バックエンドからブラウザにプッシュ通知を送信するための準備

ブラウザにプッシュ通知を送信するために、バックエンドで下記の処理をおこないます。

  1. フロントエンドで発行したエンドポイントURLやキーをバックエンドで受け取る
  2. VAPID認証
  3. プッシュ通知のリクエストボディ(メッセージ)の暗号化(AES128GCM)

重要なのは、2と3の処理ですが、今回はPHPの「minishlink/web-push(^6.0)」というライブラリを使って実現します。

バックエンドの実装

1. push通知を実装するために、minishlink/web-push(^6.0)をインストール
まずは、必要なライブラリをインストールします。


このライブラリが、VAPID認証とプッシュ通知のリクエストボディ(メッセージ)の暗号化をよしなにおこなってくれます。

2. ブラウザに通知を送信するために認証を行う
ブラウザにプッシュ通知を送信するには、認証を行う必要があります。
今回は下記のようにして実装しました。


認証に必要な情報は、次のようになります。

subject:
 通知の送信者(通知を送信するサーバー)を識別するためのURLまたはメールアドレス。
 今回はGrpMailのテスト環境のURLを指定しています。
publicKey:
 フロントエンド編のhttps://web-push-codelab.glitch.me/で発行した公開鍵を指定します。
privateKey:
 フロントエンド編のhttps://web-push-codelab.glitch.me/で発行した秘密鍵を指定します。

3. 通知を送信する
いよいよブラウザにプッシュ通知を送信します。
送信処理は下記のように実装しました。


これでプッシュ通知を送信する準備ができました!
今回実装したsend()は、新着メールを受信したときに実行されるようにしています。

プッシュ通知の送信に成功すると、ブラウザから通知が届きます!

おまけ:WebPushの再購読

実は、WebPushの購読情報には有効期限(expirationTime)が設定されている場合があります。
VAPIDかつChromeの場合は有効期限は無いらしく、常にexpirationTimeはnullを返します。
しかし、他のケースでは有効期限が切れる場合があるため、再度購読できるようにする必要があります。

購読情報変更の検知
pushsubscriptionchangeイベントで検知できるらしいですが、2024年2月現在、FireFoxとデスクトップ版のSafari以外はまだ実装されていないそうです。
(今回、FireFoxでも試してみましたがうまくいきませんでした...)

ServiceWorkerGlobalScope: pushsubscriptionchange イベント

もし、push通知の送信をフロントエンドからAPIを実行してバックエンドから送信させるなら、エラーが返ってきたときに再度購読処理を行えばいいですが、メールの受信時にpush通知させる場合はフロントエンドを介さないバックグラウンドでの実行になるため、フロントエンドにエラーを返すことができません。

そのため、購読情報の更新があれば発火するpushsubscriptionchangeイベントを使ってみたかったのですが、断念して次のようにして再購読処理を試みました。

ブラウザが購読情報を持っているかをpushManager.getSubscriptionで取得可能であり、購読情報が存在しなかったとき、pushManager.getSubscriptionはnullを返します。
つまり、現在のブラウザではまだ購読されていないので、ユーザに購読を促します。

実際の実装は今回記載しませんが、一応、再購読処理を行うことができるようになりました。

購読情報が有効期限切れであるレコードを削除する
次回から無駄なプッシュ通知を行わないように、有効期限切れになった購読情報を削除します。
具体的には、push serverからのレスポンスが410 (Gone)だった場合、該当の購読情報をDBから削除するといった処理を実装しました。
410は、指定された「subscription(購読情報)」が無効という意味になります。

引用:
If the user agent fails to acknowledge the receipt of the push
message and the push service ceases to retry delivery of the message
prior to its advertised expiration, then the push service MUST push a
failure response with a status code of 410 (Gone).
6.3. Receiving Push Message Receipts

終わりに

今回はWeb Pushを試してみましたが、新しい技術に触れることはやはり楽しいですね!
チャレンジラボではFlutterを用いたスマホアプリ開発にも取り組んでいます!

弊社では、新しいことに挑戦する社員ための教材やガジェット等の購入支援制度があります!
新しいもの好きの方、キー・ポイントで働いてみませんか?

https://www.key-p.com/recruit/

茶谷渚

茶谷渚

2022年4月に新卒で入社したサーモン大好き社員です。 プログラムを書くのが好きです。学生時代はマイコンプログラミングも少ししていました。