为什么要另辟guide径?
当我负责制作推送通知草稿时,快速搜索显示,已经有很多关于在中心上设置推送通知的文章。 我认为这是最合适的:
JS的工作原理:Web推送通知Web PUSH通知快速简便924 /服务人员。 网络推送及其住处一切都很好,但是就我个人而言,我确实缺少一个简单易懂的指南,该指南几乎可以允许我通过复制粘贴立即使一切正常运行。 好吧,此外,手册中没有适用于支持的python。
最后设置通知花了三天,在我看来,这有点太多了。 希望我的文章可以帮助某人在三小时而不是三天内设置推送通知。
我正在从事的项目是在Django上实现的,我将描述与该框架相关的工作进度,但是希望那些可以轻松地使其适应Flask或其他功能的人。
所以,走吧。
我们拿到钥匙
没有钥匙,自然地,它们不会让我们随处可见,所以让我们开始吧。 为了生成密钥,我使用了
py_vapid 。 它与
pywebpush一起自动安装,稍后我们仍然需要它,因此为避免起床两次,我们将从pywebpush开始:
> bin/pip install pywebpush < > > bin/vapid --applicationServerKey No private_key.pem file found. Do you want me to create one for you? (Y/n)Y Generating private_key.pem Generating public_key.pem Application Server Key = < Server Key>
结果应用程序服务器密钥值将添加到settings.py文件中。
NOTIFICATION_KEY = < Server Key>
另外,我们需要将NOTIFICATION_KEY传递给上下文。 最简单的方法是编写
context_processor 。
使服务人员
不知道的服务人员-这是一个在后台运行的特殊文件。 我们需要它来显示我们的通知。
最简单的服务工作者代码如下所示:
self.addEventListener('push', function(event) { var message = JSON.parse(event.data.text());
现在我们需要注册我们的服务人员。 原则上
在此描述该过程。 因此,简要地:
function checkWorkerAndPushManager () { if (!('serviceWorker' in navigator)) { console.log('Workers are not supported.'); return; } if (!('PushManager' in window)) { console.log('Push notifications are not supported.'); return; } } function registerWorker () { window.addEventListener('load', function () { navigator.serviceWorker.register('/static/js/sw.js').then(function (registration) { console.log('ServiceWorker registration successful'); }, function (err) { console.log('ServiceWorker registration failed: ', err); return; }); }); return true; } var supported = checkWorkerAndPushManager(); if (supported){ var worker = registerWorker (); }
太好了,您可以检查我们服务人员的工作。 为此,请在浏览器中转到“开发人员工具”,确保控制台上显示有关woker成功注册的消息,然后转到“应用程序”选项卡,然后选择左侧的Service Worker。

如果未出现通知,请检查是否在浏览器中启用了通知。
好吧,我们已经知道如何向自己发送通知。 酷,让我们继续前进。
获得用户显示通知的权限
注册woker后,请询问用户是否允许显示通知。
function requestPermission() { return new Promise(function(resolve, reject) { const permissionResult = Notification.requestPermission(function(result) {
此代码无需注释,它可以正常工作。
订阅并保存您的订阅
订阅也在最前面。
您可以在此处找到订阅代码 ,但是没有使用urlBase64ToUint8Array函数,因此我使用它进行了编码。
NOTIFICATION_KEY = '{{ NOTIFICATION_KEY }}; function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/') ; const rawData = window.atob(base64); return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0))); } function subscribeUserToPush(key) { return navigator.serviceWorker.register('/static/path/to/js/sw.js') .then(function(registration) { var subscribeOptions = { userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(key), }; return registration.pushManager.subscribe(subscribeOptions) }) .then(function(pushSubscription) { sendSubscriptionToBackEnd(pushSubscription); }); }
(此处使用的urlBase64ToUint8Array可能来自拐杖和自行车类,但尝试使用btoa对数据进行转码的尝试未成功,我不知道为什么。也许有人会告诉您)。
然后,我们将接收到的数据发送到服务器。 我有这样实现:
function sendSubscriptionToBackEnd(subscription) { $.post( SAVE_REGISTRATION_URL, { 'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
好吧,然后我们将其保存在服务器上。 您可以直接在线。 是的,不要尝试建立一对一的用户订阅关系。 这似乎很明显,但是突然之间任何人都想这么做。
我使用了这样一个简单的模型进行保存,稍后将使用它,因此我将给出它:
class UserSubscription(models.Model): subscription = models.CharField(max_length=500) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='subscriptions')
最后一步。 使用pywebpush发送消息
一切都在教程中,没有特殊的细微差别。 好吧,除了消息的结构使我们的服务人员可以解析它。
import json from pywebpush import webpush, WebPushException from django.conf import settings from .models import UserSubscription def push_notification(user_id): user_subscriptions = UserSubscription.objects.filter(user_id=notification.user_id) for subscription in user_subscriptions: data = json.dumps({ 'title': 'Hello', 'body': 'there', }) try: webpush( subscription_info=json.loads(subscription.subscription), data=data, vapid_private_key='./private_key.pem', vapid_claims={ 'sub': 'mailto:{}'.format(settings.ADMIN_EMAIL), } ) notification.sent = True notification.save() except WebPushException as ex: print('I\'m sorry, Dave, but I can\'t do that: {}'.format(repr(ex))) print(ex)
实际上,您已经可以从django shell调用push_notification并尝试启动。
在此代码中,截获状态为410的响应将是很好的选择。这样的回答表明预订已被取消,并且从数据库中删除此类预订也将很不错。
总结
实际上,还有另一个很棒的
django-webpush库 。 也许那些使用Django的人应该从它开始。
PS程序员节快乐!