質問編集履歴

3 誤字

Fujiman

Fujiman score 15

2019/03/02 08:49  投稿

PWAのプッシュ通知時のトークン処理の稚拙な問題
## 状況
この[サイト](https://qiita.com/y_fujieda/items/f9e765ac9d89ba241154)の「Push Notification編」を参考に
PWAでのプッシュ送信についてひと通りやりました。それに関しては問題なかったのですが
少し変えたいと変更を加えたときに、通知承認のデータを変数に受け取るという
問題が解決できず悩んでいます。
PWAとかNodeとかの以前の問題で、表題とほとんど関連性がないと思いますが・・・
## プロジェクト概要
このプロジェクトの概要は、サイトのサービスワーカーに(service-worker.js)、
'push'イベントが発生すると既定の通知内容を表示するハンドラを設定しており、
main.jsではユーザがページにアクセスした際に、通知の承諾をすると
そのEndpoint、Author、Keyをページに表示します。
別途、push.jsというファイルにそれら表示情報を埋め込んで(npmの'web-push'を使ってます)
Nodeで実行しプッシュ通知の送信をするというものです
[動作中GitHUBページ](https://kingstonelibrary.github.io/PWApush/)
[リポジトリ](https://github.com/kingstonelibrary/PWApush)
## やろうとしていること
現状ではpush.jsの実行後に通知が表示されますが、これを、ユーザが承諾した時点でプッシュ通知を表示したいと思い、main.js内の、承諾時のデータを画面表示する処理の後にpush.jsの処理を追加しようとしました
---
###### main.js(変更前)
```js
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
                .then((registration) => {
                    return registration.pushManager.subscribe({userVisibleOnly: true});
                })
                .then((subscription) => {
                    var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
                    key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
                    var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
                    auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
                    endpoint.value = subscription.endpoint;
                    console.log(`GCM EndPoint is: ${subscription.endpoint}`);
                })
                .catch(console.error.bind(console));
   }, false);
}
```
###### push.js(変更前)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
const data = {
   'endpoint': '略',
   'userAuth': '略',
   'userPublicKey': '略'
};
push.sendNotification(data.endpoint, {
   payload:      'service worker プッシュテスト',
   userAuth:     data.userAuth,
   userPublicKey: data.userPublicKey,
})
.then((result) => {
   console.log(result);
})
.catch((err) => {
   console.error('fail', err);
});
```
---
このmain.js内にpush.jsの内容を埋め込んでみたものが以下です。
画面表示に使っているデータを'web-push'に渡すオブジェクト”data”にセットしているだけです。
これをトランスパイルしてbundle.jsとし、main.jsのかわりにindex.htmlから呼びます
するとコンソールに後述のような'web-push'のエラーが出てしまいます。
ページにはAuth,Key,Endpointが表示されてはいますが。
###### App.js(main.jsにpush.jsを埋め込んだファイル)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
let data = {
   'endpoint': '',
   'userAuth': '',
   'userPublicKey': ''
};
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
       .then((registration) => {
           return registration.pushManager.subscribe({userVisibleOnly: true});
       })
       .then((subscription) => {
           var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
           key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
           var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
           auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
           endpoint.value = subscription.endpoint;
           data.endpoint = endpoint.value;
           data.userAuth = auth.value;
           data.userPublicKey = key.value;
       }).then(() => {
           push.sendNotification(data.endpoint, {
               payload:      'service worker プッシュテスト',
               userAuth:     data.userAuth,
               userPublicKey: data.userPublicKey,
           })
           .then((result) => {
               console.log(result);
           })
           .catch((err) => {
               console.error('fail', err);
           })
       }).catch(console.error.bind(console));
   }, false);
}
```
###### エラー内容
```error
fail Error: "You must pass in a subscription with at least an endpoint."
   generateRequestDetails web-push-lib.js:89 sendNotification web-push-lib.js:289 [195]</</< App.js:36
App.js:45:16
   [195]</</</< App.js:45
```
少なくともエンドポイントは渡せという意味のエラーだと思うのですが、
なぜ渡せてないのかわからず悩んでいます。
もともとは画面表示しているデータをそのままコピペして実行するpush.jsなので
どうしてこれでまずいのかがわからす悩んでいます。
処理の流れが理解できていない気がします。
オブジェクト”data”の各プロパティーに値がセットされる前に、
そのプロパティーのチェック処理が走っているような感じなのですが
また、あわせて教えていただきたいのですが、後日のプッシュ通知にも使うために
このようにユーザから得た承認のトークンなどの管理は
一般的にはどうしているのでしょうか?
どんどんDataBaseなどに保存していっているのでしょうか?
逆にブラウザの通知設定で削除されたりして承認を得られなくなったら、
その保有していた承認のデータは削除するとかでアップデートし管理しているのでしょうか?
  • Node.js

    2839 questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • npm

    483 questions

    npmは、Node Packaged Modulesの略。Node.jsのライブラリ・パッケージを管理できるツールです。様々なモジュールを簡単にインストールでき、自分でモジュールを作成し公開する際にも使用できます。

  • Babel

    87 questions

    Babelは、JavaScriptの次世代仕様であるECMAScriptのコンパイラ。次世代の標準機能を用いて記述されたコードを、それらの機能に対応していないブラウザでも動作するコードに変換することができます。

2 誤字

Fujiman

Fujiman score 15

2019/03/01 15:44  投稿

PWAのプッシュ通知時のトークン処理の稚拙な問題
## 状況
この[サイト](https://qiita.com/y_fujieda/items/f9e765ac9d89ba241154)の「Push Notification編」を参考に
PWAでのプッシュ送信についてひと通りやりました。それに関しては問題なかったのですが
少し変えたいと変更を加えたときに、通知承認のデータを変数に受け取るという
問題が解決できず悩んでいます。
PWAとかNodeとかの以前の問題で、表題とほとんど関連性がないと思いますが・・・
## プロジェクト概要
このプロジェクトの概要は、サイトのサービスワーカーに(service-worker.js)、
'push'イベントが発生すると既定の通知内容を表示するハンドラを設定しており、
main.jsではユーザがページにアクセスした際に、通知の承諾をすると
そのEndpoint、Author、Keyをページに表示します。
別途、push.jsというファイルにそれら表示情報を埋め込んで(npmの'web-push'を使ってます)
Nodeで実行しプッシュ通知の送信をするというものです
[動作中GitHUBページ](https://kingstonelibrary.github.io/PWApush/)
[リポジトリ](https://github.com/kingstonelibrary/PWApush)
## やろうとしていること
現状ではpush.jsの実行後に通知が表示されますが、これを、ユーザが承諾した時点でプッシュ通知を表示したいと思い、main.js内の、承諾時のデータを画面表示する処理の後にpush.jsの処理を追加しようとしました
---
###### main.js(変更前)
```js
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
                .then((registration) => {
                    return registration.pushManager.subscribe({userVisibleOnly: true});
                })
                .then((subscription) => {
                    var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
                    key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
                    var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
                    auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
                    endpoint.value = subscription.endpoint;
                    console.log(`GCM EndPoint is: ${subscription.endpoint}`);
                })
                .catch(console.error.bind(console));
   }, false);
}
```
###### push.js(変更前)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
const data = {
   'endpoint': '略',
   'userAuth': '略',
   'userPublicKey': '略'
};
push.sendNotification(data.endpoint, {
   payload:      'service worker プッシュテスト',
   userAuth:     data.userAuth,
   userPublicKey: data.userPublicKey,
})
.then((result) => {
   console.log(result);
})
.catch((err) => {
   console.error('fail', err);
});
```
---
このmain.js内にpush.jsの内容を埋め込んでみたものが以下です。
画面表示に使っているデータを'web-push'に渡すオブジェクト”data”にセットしているだけです。
これをトランスパイルしてbundle.jsとし、main.jsのかわりにindex.htmlから呼びます
するとコンソールに後述のような'web-push'のエラーが出てしまいます。
ページにはAuth,Key,Endpointが表示されてはいますが。  
###### App.js(main.jsにpush.jsを埋め込んだファイル)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
let data = {
   'endpoint': '',
   'userAuth': '',
   'userPublicKey': ''
};
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
       .then((registration) => {
           return registration.pushManager.subscribe({userVisibleOnly: true});
       })
       .then((subscription) => {
           var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
           key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
           var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
           auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
           endpoint.value = subscription.endpoint;
           data.endpoint = endpoint.value;
           data.userAuth = auth.value;
           data.userPublicKey = key.value;
       }).then(() => {
           push.sendNotification(data.endpoint, {
               payload:      'service worker プッシュテスト',
               userAuth:     data.userAuth,
               userPublicKey: data.userPublicKey,
           })
           .then((result) => {
               console.log(result);
           })
           .catch((err) => {
               console.error('fail', err);
           })
       }).catch(console.error.bind(console));
   }, false);
}
```
###### エラー内容
```error
fail Error: "You must pass in a subscription with at least an endpoint."
   generateRequestDetails web-push-lib.js:89 sendNotification web-push-lib.js:289 [195]</</< App.js:36
App.js:45:16
   [195]</</</< App.js:45
```
少なくともエンドポイントは渡せという意味のエラーだと思うのですが、
なぜ渡せてないのかわからず悩んでいます。
もともとは画面表示しているデータをそのままコピペして実行するpush.jsなので
どうしてこれでまずいのかがわからす悩んでいます。
処理の流れが理解できていない気がします。
オブジェクト”data”の各プロパティーに値がセットされる前に、
そのプロパティーのチェック処理が走っているような感じなのですが
また、あわせて教えていただきたいのですが、後日のプッシュ通知にも使うために
このようにユーザから得た承認のトークンなどの管理は
一般的にはどうしているのでしょうか?
どんどんDataBaseなどに保存していっているのでしょうか?
逆にブラウザの通知設定で削除されたりして承認を得られなくなったら、
その保有していた承認のデータは削除するとかでアップデートし管理しているのでしょうか?
  • Node.js

    2839 questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • npm

    483 questions

    npmは、Node Packaged Modulesの略。Node.jsのライブラリ・パッケージを管理できるツールです。様々なモジュールを簡単にインストールでき、自分でモジュールを作成し公開する際にも使用できます。

  • Babel

    87 questions

    Babelは、JavaScriptの次世代仕様であるECMAScriptのコンパイラ。次世代の標準機能を用いて記述されたコードを、それらの機能に対応していないブラウザでも動作するコードに変換することができます。

1 誤字

Fujiman

Fujiman score 15

2019/03/01 15:40  投稿

PWAのプッシュ通知時のトークン処理の稚拙な問題
## 状況
この[サイト](https://qiita.com/y_fujieda/items/f9e765ac9d89ba241154)の「Push Notification編」を参考に
少し変えたいと変更を加えたときに、通知承認のデータを変数に受け取るという
問題が解決できず悩んでいます。
PWAとかNodeとかの以前の問題で、表題とほとんど関連性がないと思いますが・・・
## プロジェクト概要
このプロジェクトの概要は、サイトのサービスワーカーに(service-worker.js)、
'push'イベントが発生すると既定の通知内容を表示するハンドラを設定しており、
main.jsではユーザがページにアクセスした際に、通知の承諾をすると
そのEndpoint、Author、Keyをページに表示します。
別途、push.jsというファイルにそれら表示情報を埋め込んで(npmの'web-push'を使ってます)
Nodeで実行しプッシュ通知の送信をするというものです
[動作中GitHUBページ](https://kingstonelibrary.github.io/PWApush/)
[リポジトリ](https://github.com/kingstonelibrary/PWApush)
## やろうとしていること
現状ではpush.jsの実行後に通知が表示されますが、これを、ユーザが承諾した時点でプッシュ通知を表示したいと思い、main.js内の、承諾時のデータを画面表示する処理の後にpush.jsの処理を追加しようとしました
---
###### main.js(変更前)
```js
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
                .then((registration) => {
                    return registration.pushManager.subscribe({userVisibleOnly: true});
                })
                .then((subscription) => {
                    var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
                    key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
                    var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
                    auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
                    endpoint.value = subscription.endpoint;
                    console.log(`GCM EndPoint is: ${subscription.endpoint}`);
                })
                .catch(console.error.bind(console));
   }, false);
}
```
###### push.js(変更前)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
const data = {
   'endpoint': '略',
   'userAuth': '略',
   'userPublicKey': '略'
};
push.sendNotification(data.endpoint, {
   payload:      'service worker プッシュテスト',
   userAuth:     data.userAuth,
   userPublicKey: data.userPublicKey,
})
.then((result) => {
   console.log(result);
})
.catch((err) => {
   console.error('fail', err);
});
```
---
このmain.js内にpush.jsの内容を埋め込んでみたものが以下です。
画面表示に使っているデータを'web-push'に渡すオブジェクト”data”にセットしているだけです。
これをトランスパイルしてbundle.jsとし、main.jsのかわりにindex.htmlから呼びます
するとコンソールに後述のような'web-push'のエラーが出てしまいます。
###### App.js(main.jsにpush.jsを埋め込んだファイル)
```js
'use strict';
let push = require('web-push');
const GCM_API_KEY = '略';
push.setGCMAPIKey(GCM_API_KEY);
let data = {
   'endpoint': '',
   'userAuth': '',
   'userPublicKey': ''
};
if ('serviceWorker' in navigator) {
   document.addEventListener('DOMContentLoaded', () => {
       let endpoint = document.querySelector('#subscription-endpoint');
       let key = document.querySelector('#subscription-public-key');
       let auth = document.querySelector('#subscription-auth');
       
       navigator.serviceWorker.register('./service-worker.js');
       navigator.serviceWorker.ready
       .then((registration) => {
           return registration.pushManager.subscribe({userVisibleOnly: true});
       })
       .then((subscription) => {
           var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
           key.value = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
           var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
           auth.value = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
           endpoint.value = subscription.endpoint;
           data.endpoint = endpoint.value;
           data.userAuth = auth.value;
           data.userPublicKey = key.value;
       }).then(() => {
           push.sendNotification(data.endpoint, {
               payload:      'service worker プッシュテスト',
               userAuth:     data.userAuth,
               userPublicKey: data.userPublicKey,
           })
           .then((result) => {
               console.log(result);
           })
           .catch((err) => {
               console.error('fail', err);
           })
       }).catch(console.error.bind(console));
   }, false);
}
```
###### エラー内容
```error
fail Error: "You must pass in a subscription with at least an endpoint."
   generateRequestDetails web-push-lib.js:89 sendNotification web-push-lib.js:289 [195]</</< App.js:36
App.js:45:16
   [195]</</</< App.js:45
```
少なくともエンドポイントは渡せという意味のエラーだと思うのですが、
なぜ渡せてないのかわからず悩んでいます。
もともとは画面表示しているデータをそのままコピペして実行するpush.jsなので
どうしてこれでまずいのかがわからす悩んでいます。
処理の流れが理解できていない気がします。
オブジェクト”data”の各プロパティーに値がセットされる前に、
そのプロパティーのチェック処理が走っているような感じなのですが
また、あわせて教えていただきたいのですが、後日のプッシュ通知にも使うために
このようにユーザから得た承認のトークンなどの管理は
一般的にはどうしているのでしょうか?
どんどんDataBaseなどに保存していっているのでしょうか?
逆にブラウザの通知設定で削除されたりして承認を得られなくなったら、
その保有していた承認のデータは削除するとかでアップデートし管理しているのでしょうか?
  • Node.js

    2839 questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • npm

    483 questions

    npmは、Node Packaged Modulesの略。Node.jsのライブラリ・パッケージを管理できるツールです。様々なモジュールを簡単にインストールでき、自分でモジュールを作成し公開する際にも使用できます。

  • Babel

    87 questions

    Babelは、JavaScriptの次世代仕様であるECMAScriptのコンパイラ。次世代の標準機能を用いて記述されたコードを、それらの機能に対応していないブラウザでも動作するコードに変換することができます。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る