2017-02-21 14 views
9

私のWebサイトにプッシュ通知サービスを開発しました。サービス労働者は次のとおりです。Web Pushnotification「UnauthorizedRegistration」または「Gone」または「Unauthorized」のサブスクリプションが終了しました

registerServiceWorker() { 
     if ('serviceWorker' in navigator) { 
      navigator.serviceWorker.register('http://localhost:5333/service-worker.js') 
       .catch((err) => { 
        this.showErrorMessage('Unable to Register SW', 'Sorry this demo requires a service worker to work and it ' + 'failed to install - sorry :('); 
        console.error(err); 
       }); 
     } else { 
      this.showErrorMessage('Service Worker Not Supported', 'Sorry this demo requires service worker support in your browser. ' + 
       'Please try this demo in Chrome or Firefox Nightly.'); 
     } 
    } 

class PushClient { 
    constructor(subscriptionUpdate, appkeys) { 
     this._subscriptionUpdate = subscriptionUpdate; 
     this._publicApplicationKey = appkeys; 
     if (!('serviceWorker' in navigator)) { 
      return; 
     } 
     if (!('PushManager' in window)) { 
      return; 
     } 
     if (!('showNotification' in ServiceWorkerRegistration.prototype)) { 
      return; 
     } 
     navigator.serviceWorker.ready.then(() => { 
      this.setUpPushPermission(); 
     }); 
    } 
    setUpPushPermission() { 
     return navigator.serviceWorker.ready.then((serviceWorkerRegistration) => { 
      return serviceWorkerRegistration.pushManager.getSubscription(); 
     }) 
      .then((subscription) => { 
       if (!subscription) { 
        return; 
       } 
       this._subscriptionUpdate(subscription); 
      }) 
      .catch((err) => { 
       console.log('setUpPushPermission() ', err); 
      }); 
    } 
    subscribeDevice() { 
     return new Promise((resolve, reject) => { 
      if (Notification.permission === 'denied') { 
       sc(3); 
       return reject(new Error('Push messages are blocked.')); 
      } 
      if (Notification.permission === 'granted') { 
       sc(3); 
       return resolve(); 
      } 
      if (Notification.permission === 'default') { 
       Notification.requestPermission((result) => { 
        if (result === 'denied') { 
         sc(0); 
        } else if (result === 'granted') { 
         sc(1); 
        } else { 
         sc(2); 
        } 
        if (result !== 'granted') { 
         reject(new Error('Bad permission result')); 
        } 
        resolve(); 
       }); 
      } 
     }) 
      .then(() => { 
       return navigator.serviceWorker.ready.then((serviceWorkerRegistration) => { 
        return serviceWorkerRegistration.pushManager.subscribe({ 
         userVisibleOnly: true 
         , applicationServerKey: this._publicApplicationKey.publicKey 
        , 
        }); 
       }) 
        .then((subscription) => { 
         this._subscriptionUpdate(subscription); 
         if (subscription) { 
          this.sendPushMessage(subscription); 
         } 
        }) 
        .catch((subscriptionErr) => { }); 
      }) 
      .catch(() => { }); 
    } 
    toBase64(arrayBuffer, start, end) { 
     start = start || 0; 
     end = end || arrayBuffer.byteLength; 
     const partialBuffer = new Uint8Array(arrayBuffer.slice(start, end)); 
     return btoa(String.fromCharCode.apply(null, partialBuffer)); 
    } 
    unsubscribeDevice() { 
     navigator.serviceWorker.ready.then((serviceWorkerRegistration) => { 
      return serviceWorkerRegistration.pushManager.getSubscription(); 
     }) 
      .then((pushSubscription) => { 
       if (!pushSubscription) { 
        this._subscriptionUpdate(null); 
        return; 
       } 
       return pushSubscription.unsubscribe() 
        .then(function (successful) { 
         if (!successful) { 
          console.error('We were unable to unregister from push'); 
         } 
        }); 
      }) 
      .then(() => { 
       this._subscriptionUpdate(null); 
      }) 
      .catch((err) => { 
       console.error('Error thrown while revoking push notifications. ' + 'Most likely because push was never registered', err); 
      }); 
    } 
    sendPushMessage(subscription) { 
     let payloadPromise = Promise.resolve(null); 
     payloadPromise = JSON.parse(JSON.stringify(subscription)); 
     const vapidPromise = EncryptionHelperFactory.createVapidAuthHeader(this._publicApplicationKey, subscription.endpoint, 'http://localhost:5333/'); 
     return Promise.all([payloadPromise, vapidPromise, ]) 
      .then((results) => { 
       const payload = results[0]; 
       const vapidHeaders = results[1]; 
       let infoFunction = this.getWebPushInfo; 
       infoFunction =() => { 
        return this.getWebPushInfo(subscription, payload, vapidHeaders); 
       }; 
       const requestInfo = infoFunction(); 
       this.sendRequestToProxyServer(requestInfo); 
      }); 
    } 
    getWebPushInfo(subscription, payload, vapidHeaders) { 
     let body = null; 
     const headers = {}; 
     headers.TTL = 60; 
     if (payload) { 
      headers.Encryption = `auth=${payload.keys.auth}`; 
      headers['Crypto-Key'] = `p256dh=${payload.keys.p256dh}`; 
      headers['Content-Encoding'] = 'aesgcm'; 
     } else { 
      headers['Content-Length'] = 0; 
     } 
     if (vapidHeaders) { 
      headers.Authorization = `WebPush ${vapidHeaders.authorization}`; 
      if (headers['Crypto-Key']) { 
       headers['Crypto-Key'] = `${headers['Crypto-Key']}; ` + `p256ecdsa=${vapidHeaders.p256ecdsa}`; 
      } else { 
       headers['Crypto-Key'] = `p256ecdsa=${vapidHeaders.p256ecdsa}`; 
      } 
     } 
     const response = { 
      headers: headers 
      , endpoint: subscription.endpoint 
     , 
     }; 
     if (body) { 
      response.body = body; 
     } 
     return response; 
    } 
    sendRequestToProxyServer(requestInfo) { 
     const fetchOptions = { 
      method: 'post' 
     , 
     }; 
     if (requestInfo.body && requestInfo.body instanceof ArrayBuffer) { 
      requestInfo.body = this.toBase64(requestInfo.body); 
      fetchOptions.body = requestInfo; 
     } 
     fetchOptions.body = JSON.stringify(requestInfo); 
     fetch('http://localhost:5333/usrh.ashx', fetchOptions) 
      .then(function (response) { 
       if (response.status >= 400 && response.status < 500) { 
        console.log('Failed web push response: ', response, response.status); 
        throw new Error('Failed to send push message via web push protocol'); 
       } 
      }) 
      .catch((err) => { 
       this.showErrorMessage('Ooops Unable to Send a Push', err); 
      }); 
    } 
} 

これらのすべてのコードはJavaScriptである:

'use strict'; 
    self.addEventListener('push', function (event) {  
    var msg = {}; 
    if (event.data) { 
     msg = event.data.json(); 
    }  
    let notificationTitle = msg.title; 
    const notificationOptions = { 
     body: msg.body,//body 
     dir:'rtl',//direction 
     icon: msg.icon,//image 
     data: { 
      url: msg.url,//click 
     }, 
    }; 
    event.waitUntil(
     Promise.all([ 
     self.registration.showNotification(
      notificationTitle, notificationOptions),  
     ]) 
    ); 
    }); 
    self.addEventListener('notificationclick', function (event) {  
     event.notification.close(); 

    let clickResponsePromise = Promise.resolve(); 
    if (event.notification.data && event.notification.data.url) { 
     clickResponsePromise = clients.openWindow(event.notification.data.url); 
    } 
    const fetchOptions = 
     { method: 'post'}; 
    fetch('http://localhost:5333/usrh.ashx?click=true', fetchOptions). 
    then(function (response) 
    { 
     if (response.status >= 400 && response.status < 500) 
     {   
      throw new Error('Failed to send push message via web push protocol'); 
     } 
    }).catch((err) => 
    { 
     this.showErrorMessage('Ooops Unable to Send a Click', err); 
    }); 
}); 

self.addEventListener('notificationclose', function (event) { 
    const fetchOptions = 
     { method: 'post'}; 
    fetch('http://localhost:5333/usrh.ashx?close=true', fetchOptions). 
    then(function (response) 
    { 
     if (response.status >= 400 && response.status < 500) 
     {   
      throw new Error('Failed to send push message via web push protocol'); 
     } 
    }).catch((err) => 
    { 
     this.showErrorMessage('Ooops Unable to Send a Click', err); 
    }); 
}); 
self.addEventListener('pushsubscriptionchange', function() { 
    const fetchOptions = { 
     method: 'post' 
     , 
    }; 

    fetch('http://localhost:5333/usru.ashx', fetchOptions) 
     .then(function (response) { 
      if (response.status >= 400 && response.status < 500) { 
       console.log('Failed web push response: ', response, response.status); 
       throw new Error('Failed to update users.'); 
      } 
     }) 
     .catch((err) => { 
      this.showErrorMessage('Ooops Unable to Send a user', err); 
     }); 
}); 

私は正常に次のコードを使用してユーザーを登録しています。私のような私のサーバー上で正常にレシーブのユーザーサブスクリプションinfromarionことができます。

Authorization: WebPush eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwcxxxxx 
Crypto-Key: p256dh=BBp90dwDWxxxxc1TfdBjFPqxxxxxwjO9fCip-K_Eebmg=; p256ecdsa=BDd3_hVL9fZi9Yboxxxxxxo 
endpoint: https://fcm.googleapis.com/fcm/send/cxxxxxxxxxxxxxxJRorOMHKLQ3gtT7 
Encryption: auth=9PzQZ1mut99qxxxxxxxxxxyw== 
Content-Encoding: aesgcm 

はまた、私は首尾よく怒鳴るC#でコードを使用して、このユーザーにプッシュを送ることができます。

public static async Task<bool> SendNotificationByte(string endpoint, string[] Keys, byte[] userSecret, byte[] data = null, 
             int ttl = 0, ushort padding = 0, bool randomisePadding = false, string auth="") 
     { 
      #region send 
      HttpRequestMessage Request = new HttpRequestMessage(HttpMethod.Post, endpoint);     
       Request.Headers.TryAddWithoutValidation("Authorization", auth); 
      Request.Headers.Add("TTL", ttl.ToString()); 
      if (data != null && Keys[1] != null && userSecret != null) 
      { 
       EncryptionResult Package = EncryptMessage(Decode(Keys[1]), userSecret, data, padding, randomisePadding); 
       Request.Content = new ByteArrayContent(Package.Payload); 
       Request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
       Request.Content.Headers.ContentLength = Package.Payload.Length; 
       Request.Content.Headers.ContentEncoding.Add("aesgcm"); 
       Request.Headers.Add("Crypto-Key", "dh=" + Encode(Package.PublicKey)+" ;"+Keys[2]+"="+Keys[3]); 
       Request.Headers.Add("Encryption", "salt=" + Encode(Package.Salt)); 
      } 
      using (HttpClient HC = new HttpClient()) 
      { 
       HttpResponseMessage res = await HC.SendAsync(Request).ConfigureAwait(false); 
       if (res.StatusCode == HttpStatusCode.Created) 
        return true; 
       else return false; 
      } 
      #endregion 
     } 

問題があり、その期間の後時間(約20時間またはそれ以下)、私はこのユーザーにプッシュを送信する場合、私は次のエラーを得た:

Firefoxのサブスクリプション:

{StatusCode: 410, ReasonPhrase: 'Gone', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: 
{ 
    Access-Control-Allow-Headers: content-encoding,encryption,crypto-key,ttl,encryption-key,content-type,authorization 
    Access-Control-Allow-Methods: POST 
    Access-Control-Allow-Origin: * 
    Access-Control-Expose-Headers: location,www-authenticate 
    Connection: keep-alive 
    Cache-Control: max-age=86400 
    Date: Tue, 21 Feb 2017 08:19:03 GMT 
    Server: nginx 
    Content-Length: 179 
    Content-Type: application/json 
}} 

クロームサブスクリプション:私は私が何かを逃したと思います

{StatusCode: 400, ReasonPhrase: 'UnauthorizedRegistration', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: 
{ 
    X-Content-Type-Options: nosniff 
    X-Frame-Options: SAMEORIGIN 
    X-XSS-Protection: 1; mode=block 
    Alt-Svc: quic=":443"; ma=2592000; v="35,34" 
    Vary: Accept-Encoding 
    Transfer-Encoding: chunked 
    Accept-Ranges: none 
    Cache-Control: max-age=0, private 
    Date: Tue, 21 Feb 2017 08:18:35 GMT 
    Server: GSE 
    Content-Type: text/html; charset=UTF-8 
    Expires: Tue, 21 Feb 2017 08:18:35 GMT 
}} 

、サブスクリプションの有効期限が切れる、またはそのサブスクリプション情報が変更または有効期限が切れたときに、ユーザーが再サブスクライブするために確認する必要がありますが、私はどのように知っていない可能! !

答えて

1

問題は、サブスクライブしたユーザーにプッシュエコー通知を送信して再サブスクライブすることで解決します。私は定期的にプッシュエコーを送信し、ユーザーを再登録して情報を更新する仕事を書いています。あなたができるresubscription方法unsubscribe

self.addEventListener('push', function (event) { 
lastEventName = 'push'; 
var msg = {}; 
if (event.data) { 
    msg = event.data.json(); 
    if (!!msg.isEcho) { 
     self.registration.pushManager.getSubscription() 
      .then(function (subscription) { 
       if (!subscription) { 
       } else { 
        subscription.unsubscribe().then(function() { 
         self.registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: base64UrlToUint8Array('xxxxxxxxxxxxxxxx') }) 
          .then(function (subscription) { 
           resubscription(subscription); 
          }); 
        }); 
        } 
      }); 
     return; 
    } 
} 
if (!!msg.isEcho) 
    return; 
let notificationTitle = msg.title; 
const notificationOptions = { 
    body: msg.body, 
    dir: 'rtl', 
    icon: msg.icon, 
    data: { 
     url: msg.url, 
     id: msg.id, 
     key: msg.key 
    }, 
}; 
event.waitUntil(
    Promise.all([ 
    self.registration.showNotification(
     notificationTitle, notificationOptions), 
    ]) 
); 

const fetchOptions = 
    { method: 'post', mode: 'no-cors' }; 
fetch('http://example.com', fetchOptions). 
    then(function (response) { 
     if (response.status >= 400 && response.status < 500) { 
      throw new Error('Failed to send push message via web push protocol'); 
     } 
     lastEventName = 'view'; 
    }).catch((err) => { 
     this.showErrorMessage('Ooops Unable to Send a Click', err); 
    }); 
}); 

、その後subscribeユーザーを、サーバーのデータを更新:私は怒鳴るコードを使用して、「エコー押し」と呼ばれる特別なメッセージを送って、そうするには

1

いくつかの手がかり:

SWは、プッシュイベントが到着した時点で、登録して起動する必要があります。つまり、セッションをクリーンアップしたり、プライベートブラウジングモードを使用したり、間にコンピュータのキャッシュをクリーンアップしたりすることはできません。

プッシュイベントは同じ起点から来なければなりません。

1

私はあなたのapplicationServerKeyを送信する方法についての問題だと思います。私はちょうどあなたが何をしたいの例を行っていると私は、この関数でエンコードされ、そのキーを送信する必要がありました:

そう
function urlBase64ToUint8Array(base64String) { 
    const padding = '='.repeat((4 - base64String.length % 4) % 4); 
    const base64 = (base64String + padding) 
     .replace(/\-/g, '+') 
     .replace(/_/g, '/'); 

    const rawData = window.atob(base64); 
    const outputArray = new Uint8Array(rawData.length); 

    for (let i = 0; i < rawData.length; ++i) { 
     outputArray[i] = rawData.charCodeAt(i); 
    } 
    return outputArray; 
    } 

あなたはこの方法であなたのサブスクリプション・オブジェクトを作成する必要があります。

registration.pushManager 
    .subscribe({ 
     userVisibleOnly: true, 
     applicationServerKey: urlBase64ToUint8Array(this._publicApplicationKey.publicKey), 
    }) 

主に私がしたのは、this tutorialです。 その実例はthis github repoです。 READMEファイルはスペイン語ですが、それはあなたを助けることができると思います。

+0

私はそうは思わない!これが解決策であれば、プッシュ通知を送信することはできませんでした。私が言及したように私は約20時間でユーザーに送ることができます!その後、定期購読期限が切れているようです! – Alex

+0

このコードがエスケートされる前に私はすでに自分の鍵を符号化しています。 – Alex

2

問題を解決するには、ユーザーの再登録が必要です。

関連する問題