ウェブプッシュを使用する際の課題の一つは、プッシュ メッセージをトリガーするのが非常に面倒なことです。プッシュ メッセージをトリガーするには、アプリケーションが ウェブ プッシュ プロトコルに従ってプッシュ サービスに POST リクエストを送信する必要があります。すべてのブラウザでプッシュを使用するには、VAPID(アプリケーション サーバーキー)を使用する必要があります。これは基本的に、アプリケーションがユーザーにメッセージを送信できることを証明する値を含むヘッダーを設定する必要があります。プッシュ メッセージでデータを送信するには、データを暗号化し、ブラウザがメッセージを正しく復号できるように特定のヘッダーを追加する必要があります。
プッシュをトリガーする主な問題は、問題が発生した場合に問題を診断するのが難しいことです。時間の経過とともに、より多くのブラウザでサポートされるようになってはいますが、簡単ではありません。そのため、ライブラリを使用して、プッシュ メッセージの暗号化、フォーマット、トリガーを処理することを強くおすすめします。
ライブラリが何をしているのか詳しく知りたい場合は、次のセクションで説明します。ここでは、サブスクリプションの管理と、既存のウェブプッシュ ライブラリを使用してプッシュ リクエストを行う方法について説明します。
このセクションでは、web-push Node ライブラリを使用します。他の言語では違いがありますが、それほど大きくはありません。Node は JavaScript であり、読者にとって最もアクセスしやすいものであるため、Node を検討しています。
手順は次のとおりです。
- サブスクリプションをバックエンドに送信して保存します。
- 保存したサブスクリプションを取得し、プッシュ メッセージをトリガーします。
定期購入の保存
データベースからの PushSubscription
の保存とクエリは、サーバーサイドの言語と選択したデータベースによって異なりますが、その方法の例を示すのは有用かもしれません。
デモのウェブページでは、簡単な POST リクエストを送信して PushSubscription
をバックエンドに送信します。
function sendSubscriptionToBackEnd(subscription) {
return fetch('/api/save-subscription/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(subscription),
})
.then(function (response) {
if (!response.ok) {
throw new Error('Bad status code from server.');
}
return response.json();
})
.then(function (responseData) {
if (!(responseData.data && responseData.data.success)) {
throw new Error('Bad response from server.');
}
});
}
デモの Express サーバーは、/api/save-subscription/
エンドポイントに一致するリクエスト リスナーを備えています。
app.post('/api/save-subscription/', function (req, res) {
このルートでは、リクエストが正常でゴミがないことを確認するために、サブスクリプションを検証します。
const isValidSaveRequest = (req, res) => {
// Check the request body has at least an endpoint.
if (!req.body || !req.body.endpoint) {
// Not a valid subscription.
res.status(400);
res.setHeader('Content-Type', 'application/json');
res.send(
JSON.stringify({
error: {
id: 'no-endpoint',
message: 'Subscription must have an endpoint.',
},
}),
);
return false;
}
return true;
};
サブスクリプションが有効な場合は、それを保存して適切な JSON レスポンスを返す必要があります。
return saveSubscriptionToDatabase(req.body)
.then(function (subscriptionId) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({data: {success: true}}));
})
.catch(function (err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(
JSON.stringify({
error: {
id: 'unable-to-save-subscription',
message:
'The subscription was received but we were unable to save it to our database.',
},
}),
);
});
このデモでは nedb を使用してサブスクリプションを保存します。これは単純なファイルベースのデータベースですが、任意のデータベースを使用できます。設定が不要なため、この方法のみを使用しています。本番環境では、より信頼性の高いものを使用することをおすすめします。(私は古い MySQL に固執する傾向があります)。
function saveSubscriptionToDatabase(subscription) {
return new Promise(function (resolve, reject) {
db.insert(subscription, function (err, newDoc) {
if (err) {
reject(err);
return;
}
resolve(newDoc._id);
});
});
}
プッシュ メッセージの送信
プッシュ メッセージを送信するには、最終的には、ユーザーにメッセージを送信するプロセスをトリガーするイベントが必要です。一般的なアプローチは、プッシュ メッセージを構成してトリガーできる管理ページを作成することです。ただし、ローカルで実行するプログラムを作成したり、PushSubscription
のリストにアクセスしてコードを実行して push メッセージをトリガーする他の方法を採用したりできます。
デモには、プッシュをトリガーできる「管理者のような」ページがあります。これは単なるデモであるため、公開ページです。
デモを動作させるための手順を順に説明します。初心者の方でも理解できるように、簡単な手順で説明します。
ユーザーの登録について説明した際に、subscribe()
オプションに applicationServerKey
を追加しました。この秘密鍵はバックエンドで必要になります。
デモでは、これらの値は次のように Node アプリに追加されます(退屈なコードですが、魔法はないことをお知らせします)。
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
次に、Node サーバーの web-push
モジュールをインストールする必要があります。
npm install web-push --save
次に、Node スクリプトで web-push
モジュールを次のように必要とします。
const webpush = require('web-push');
これで、web-push
モジュールの使用を開始できます。まず、アプリケーション サーバー鍵について web-push
モジュールに伝える必要があります。(これらのキーは、仕様の名称である VAPID キーとも呼ばれます)。
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
「mailto:」文字列も含まれています。この文字列は、URL または mailto メールアドレスのいずれかである必要があります。この情報は、プッシュをトリガーするリクエストの一部として、ウェブ プッシュ サービスに送信されます。これは、ウェブプッシュ サービスが送信者と連絡を取る必要がある場合に、連絡を取るための情報が得られるようにするためです。
これで、web-push
モジュールは使用できる状態になりました。次のステップは、プッシュ メッセージをトリガーすることです。
このデモでは、疑似管理パネルを使用してプッシュ メッセージをトリガーします。
[Trigger Push Message] ボタンをクリックすると、/api/trigger-push-msg/
に POST リクエストが送信されます。これは、バックエンドが push メッセージを送信するためのシグナルです。このエンドポイントのルートを Express で作成します。
app.post('/api/trigger-push-msg/', function (req, res) {
このリクエストを受信すると、データベースからサブスクリプションを取得し、それぞれに対して push メッセージをトリガーします。
return getSubscriptionsFromDatabase().then(function (subscriptions) {
let promiseChain = Promise.resolve();
for (let i = 0; i < subscriptions.length; i++) {
const subscription = subscriptions[i];
promiseChain = promiseChain.then(() => {
return triggerPushMsg(subscription, dataToSend);
});
}
return promiseChain;
});
関数 triggerPushMsg()
は、web-push ライブラリを使用して、指定されたサブスクリプションにメッセージを送信できます。
const triggerPushMsg = function (subscription, dataToSend) {
return webpush.sendNotification(subscription, dataToSend).catch((err) => {
if (err.statusCode === 404 || err.statusCode === 410) {
console.log('Subscription has expired or is no longer valid: ', err);
return deleteSubscriptionFromDatabase(subscription._id);
} else {
throw err;
}
});
};
webpush.sendNotification()
の呼び出しは Promise を返します。メッセージが正常に送信された場合、Promise は解決し、何もする必要はありません。Promise が拒否された場合は、PushSubscription
がまだ有効かどうかを通知するため、エラーを調べる必要があります。
プッシュ サービスからエラーの種類を判断するには、ステータス コードを確認することをおすすめします。エラー メッセージはプッシュ サービスによって異なり、一部は他よりも役立ちます。
この例では、ステータス コード 404
と 410
を確認します。これは、「見つかりません」と「存在しない」の HTTP ステータス コードです。これらのいずれかが表示された場合は、定期購入が期限切れか無効であることを意味します。このような場合は、データベースから定期購入を削除する必要があります。
その他のエラーの場合は、単に throw err
します。これにより、triggerPushMsg()
によって返された Promise が拒否されます。
他のステータス コードについては、次のセクションでウェブプッシュ プロトコルを詳しく説明する際に説明します。
定期購入をループした後、JSON レスポンスを返す必要があります。
.then(() => {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ data: { success: true } }));
})
.catch(function(err) {
res.status(500);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({
error: {
id: 'unable-to-send-messages',
message: `We were unable to send messages to all subscriptions : ` +
`'${err.message}'`
}
}));
});
主な実装手順は次のとおりです。
- ウェブページからバックエンドに定期購入を送信し、バックエンドでデータベースに保存できるようにする API を作成します。
- プッシュ メッセージの送信をトリガーする API を作成します(この場合は、偽の管理パネルから呼び出される API)。
- バックエンドからすべてのサブスクリプションを取得し、ウェブプッシュ ライブラリのいずれかを使用して各サブスクリプションにメッセージを送信します。
バックエンド(Node、PHP、Python など)に関係なく、プッシュを実装する手順は同じです。
次に、これらのウェブプッシュ ライブラリが具体的に何をしてくれるのかを見てみましょう。
次のステップ
- ウェブでのプッシュ通知の概要
- プッシュの仕組み
- ユーザーを登録する
- 権限の UX
- ウェブプッシュ ライブラリによるメッセージの送信
- ウェブ プッシュ プロトコル
- プッシュ イベントの処理
- 通知の表示
- 通知の動作
- 一般的な通知パターン
- プッシュ通知に関するよくある質問
- 一般的な問題とバグの報告