如何从Django应用程序发送Web推送通知

2018-11-15 15:32:14 浏览数 (1)

介绍

网络不断发展,现在可以实现以前只能在本机移动设备上使用的功能。JavaScript 服务工作者的引入为Web提供了新的功能,可以执行后台同步,脱机缓存和发送推送通知等功能。

推送通知允许用户选择接收移动和Web应用程序的更新。它们还使用户能够使用自定义和相关内容重新使用现有应用程序。

在本教程中,您将在Ubuntu 18.04上设置一个Django应用程序,只要有需要用户访问应用程序的活动,就会发送推送通知。要创建这些通知,您将使用Django-Webpush包并设置和注册服务工作者以向客户端显示通知。带通知的工作应用程序如下所示:

先决条件

在开始本指南之前,您需要以下内容:

  • 一个Ubuntu 18.04服务器,具有非root用户和活动防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器。
  • 遵循这些准则安装pipvenv
  • 在您的主目录中创建一个名为djangopush的项目,按照这些关于在Ubuntu上创建示例Django项目的指南进行设置。务必将服务器的IP地址添加到settings.py文件中ALLOWED_HOSTS的指令中。

第1步 - 安装Django-Webpush并获取Vapid密钥

Django-Webpush是一个允许开发人员在Django应用程序中集成和发送Web推送通知的软件包。我们将使用此包来触发和发送来自我们应用程序的推送通知。在此步骤中,您将安装Django-Webpush并获取识别服务器所需的自愿应用程序服务器标识(VAPID)密钥,并确保每个请求的唯一性。

确保您位于先决条件中创建的~/djangopush项目目录中:

代码语言:javascript复制
cd ~/djangopush

激活您的虚拟环境:

代码语言:javascript复制
source my_env/bin/activate

升级您的pip版本以确保它是最新的:

代码语言:javascript复制
pip install --upgrade pip

安装Django-Webpush:

代码语言:javascript复制
pip install django-webpush

安装软件包后,将其添加到settings.py文件中的应用程序列表中。首先打开settings.py

代码语言:javascript复制
nano ~/djangopush/djangopush/settings.py

添加webpush到以下INSTALLED_APPS列表中:

代码语言:javascript复制
...
​
INSTALLED_APPS = [
    ...,
    'webpush',
]
...

保存文件并退出编辑器。

在应用程序上运行迁移以应用您对数据库模式所做的更改:

代码语言:javascript复制
python manage.py migrate

输出将如下所示,表示迁移成功:

代码语言:javascript复制
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, webpush
Running migrations:
  Applying webpush.0001_initial... OK

设置Web推送通知的下一步是获取VAPID密钥。这些密钥标识应用程序服务器,可用于减少推送订阅URL的保密性,因为它们限制对特定服务器的订阅。

要获取VAPID密钥,请导航到wep-push-codelab Web应用程序。在这里,您将获得自动生成的密钥。复制私钥和公钥。

接下来,在settings.py中为您的VAPID信息创建一个新条目。首先,打开文件:

代码语言:javascript复制
nano ~/djangopush/djangopush/settings.py

接下来,使用您的VAPID公钥和私钥创建一个名为WEBPUSH_SETTINGS的新指令以及在下AUTH_PASSWORD_VALIDATORS面的电子邮件:

代码语言:javascript复制
...
​
AUTH_PASSWORD_VALIDATORS = [
    ...
]
​
WEBPUSH_SETTINGS = {
   "VAPID_PUBLIC_KEY": "your_vapid_public_key",
   "VAPID_PRIVATE_KEY": "your_vapid_private_key",
   "VAPID_ADMIN_EMAIL": "admin@example.com"
}
​
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
​
...

不要忘了使用自己的信息替换值为your_vapid_public_keyyour_vapid_private_key以及admin@example.com的占位符。如果推送服务器遇到任何问题,您的电子邮件地址就是通知您的方式。

接下来,我们将设置视图,以显示应用程序的主页并向订阅用户触发推送通知。

第2步 - 设置视图

在此步骤中,我们将使用HttpResponse响应对象来设置基本的home 视图send_push视图。视图是从Web请求返回响应对象的函数。该 send_push 视图将使用Django-Webpush库发送包含用户在主页上输入的数据的推送通知。

导航到该~/djangopush/djangopush文件夹:

代码语言:javascript复制
cd ~/djangopush/djangopush

在文件夹内运行ls将显示项目的主文件:

代码语言:javascript复制
/__init__.py
/settings.py
/urls.py
/wsgi.py

此文件夹中的文件由您用于在先决条件中创建项目的django-admin实用程序自动生成。该settings.py文件包含项目范围的配置,如已安装的应用程序和静态根文件夹。该urls.py文件包含项目的URL配置。您可以在此处设置路线以匹配您创建的视图。

~/djangopush/djangopush目录中创建一个名为 views.py的新文件,该文件将包含项目的视图:

代码语言:javascript复制
nano ~/djangopush/djangopush/views.py

我们要做的第一个视图是home视图,它将显示用户可以发送推送通知的主页。将以下代码添加到文件中:

代码语言:javascript复制
from django.http.response import HttpResponse
from django.views.decorators.http import require_GET
​
@require_GET
def home(request):
    return HttpResponse('<h1>Home Page<h1>')

home视图是由require_GET装饰,其中规定只有GET请求的观点。视图通常会为每个请求返回响应。此视图返回一个简单的HTML标记作为响应。

我们将创建的下一个视图是send_push,它将处理使用该django-webpush包发送的推送通知。它仅限于POST请求,并且将免于跨站请求伪造(CSRF)保护。这样做将允许您使用Postman或任何其他RESTful服务测试视图。但是,在生产中,您应该删除此装饰器,以避免您的视图容易受到CSRF的影响。

要创建send_push视图,首先添加以下导入以启用JSON响应并访问webpush库中的send_user_notification函数:

代码语言:javascript复制
from django.http.response import JsonResponse, HttpResponse
from django.views.decorators.http import require_GET, require_POST
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
from webpush import send_user_notification
import json

接下来,添加require_POST装饰器,它将使用用户发送的请求主体来创建并触发推送通知:

代码语言:javascript复制
@require_GET
def home(request):
    ...
​
​
@require_POST
@csrf_exempt
def send_push(request):
    try:
        body = request.body
        data = json.loads(body)
​
        if 'head' not in data or 'body' not in data or 'id' not in data:
            return JsonResponse(status=400, data={"message": "Invalid data format"})
​
        user_id = data['id']
        user = get_object_or_404(User, pk=user_id)
        payload = {'head': data['head'], 'body': data['body']}
        send_user_notification(user=user, payload=payload, ttl=1000)
​
        return JsonResponse(status=200, data={"message": "Web push successful"})
    except TypeError:
        return JsonResponse(status=500, data={"message": "An error occurred"})

我们在send_push视图中使用了两个装饰器:require_POST装饰器,它将视图限制为仅仅POST请求,以及csrf_exempt装饰器,它将视图从CSRF保护中免除。

此视图需要POST数据并执行以下操作:它获取请求的body内容,并使用json包将JSON文档反序列化为使用json.loads的Python对象。json.loads获取结构化JSON文档并将其转换为Python对象。

视图期望请求主体对象具有三个属性:

  • head:推送通知的标题。
  • body:通知的正文。
  • idid请求用户的。

如果缺少任何必需的属性,视图将返回JSONResponse并且呈现404“未找到”的状态。如果与给定的主密钥的用户存在,该视图将使用所述匹配的主键来返回user,该主键使用来自django.shortcuts库的get_object_or_404函数。如果用户不存在,该函数将返回404错误。

该视图还使用了webpush库中的send_user_notification函数。该函数有三个参数:

  • User:推送通知的收件人。
  • payload:通知信息,包括通知headbody
  • ttl:用户脱机时应存储通知的最长时间(以秒为单位)。

如果没有错误发生,视图将返回JSONResponse并且呈现200“成功”的状态和一个数据对象。如果KeyError发生,则视图将返回500“内部服务器错误”状态。当对象的请求键不存在时发生KeyError.

在下一步中,我们将创建相应的URL路由以匹配我们创建的视图。

第3步 - 将URL映射到视图

Django可以创建使用名为URLconf的Python模块连接到视图的URL。此模块将URL路径表达式映射到Python函数(您的视图)。通常,在创建项目时会自动生成URL配置文件。在此步骤中,您将更新此文件以包含您在上一步中创建的视图的新路由以及django-webpush应用程序的URL ,这将为订阅用户提供推送通知的端点。

开放urls.py

代码语言:javascript复制
nano ~/djangopush/djangopush/urls.py

该文件将如下所示:

代码语言:javascript复制
"""untitled URL Configuration
​
The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
​
urlpatterns = [
    path('admin/', admin.site.urls),
]

下一步是将您创建的视图映射到URL。首先,添加include输入以确保将Django-Webpush库的所有路由添加到项目中:

代码语言:javascript复制
"""webpushdjango URL Configuration
...
"""
from django.contrib import admin
from django.urls import path, include

接下来,导入您在上一步中创建的视图,并更新urlpatterns列表以映射您的视图:

代码语言:javascript复制
"""webpushdjango URL Configuration
...
"""
from django.contrib import admin
from django.urls import path, include
​
from .views import home, send_push
​
urlpatterns = [
                  path('admin/', admin.site.urls),
                  path('', home),
                  path('send_push', send_push),
                  path('webpush/', include('webpush.urls')),
              ]

此处,urlpatterns列表会注册django-webpush包的URL,并将您的视图映射到URL /send_push/home

让我们测试/home视图以确保它按预期工作。确保您位于项目的根目录中:

代码语言:javascript复制
cd ~/djangopush

运行以下命令启动服务器:

代码语言:javascript复制
python manage.py runserver your_server_ip:8000

导航到http://your_server_ip:8000。您应该看到以下主页:

此时,您可以使用该CTRL C命令终止服务器,我们将继续创建模板并使用该render功能在视图中呈现它们。

第4步 - 创建模板

Django的模板引擎允许您使用与HTML文件类似的模板定义应用程序的面向用户层。在此步骤中,您将为home视图创建和呈现模板。

在项目的根目录中创建一个名为templates的文件夹:

代码语言:javascript复制
mkdir ~/djangopush/templates

如果此时在项目的根文件夹中运行ls,输出将如下所示:

代码语言:javascript复制
/djangopush
/templates
db.sqlite3
manage.py
/my_env

templates文件夹中创建一个名为home.html的文件:

代码语言:javascript复制
nano ~/djangopush/templates/home.html

将以下代码添加到文件中以创建一个表单,用户可以在其中输入信息以创建推送通知:

代码语言:javascript复制
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="vapid-key" content="{{ vapid_key }}">
    {% if user.id %}
        <meta name="user_id" content="{{ user.id }}">
    {% endif %}
    <title>Web Push</title>
    <link href="https://fonts.googleapis.com/css?family=PT Sans:400,700" rel="stylesheet">
</head>
​
<body>
<div>
    <form id="send-push__form">
        <h3 class="header">Send a push notification</h3>
        <p class="error"></p>
        <input type="text" name="head" placeholder="Header: Your favorite airline 


	

0 人点赞