通过 Python 注册 Service Worker 时 serverApplicationKey 无效

问题描述

在进行 Service Worker 订阅时,我不断收到此错误“未处理的拒绝(InvalidAccessError):无法在‘PushManager’上执行‘订阅’:提供的 applicationServerKey 无效”。我不知道是什么导致了这个问题。我正在尝试使用 Flask 和 React 从服务器向客户端发送推送通知。我不知道密钥是否错误,没有在服务器中注册 vapid 密钥,或者其他什么。有人可以帮我吗?


routes.py

from database.models import User,Reminder
from database import app,request,bcrypt,db
import json
from flask_login import login_user,logout_user,current_user,login_required
from flask import jsonify
import sys
import jwt
from functools import wraps
import datetime
import datetime
import time
from database import modules
import base64

vapid_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0GpiI5nprbMjvyXkWgCP43XZDBmuECPl4E/w3f7yJL+kuPEFmbYT75q/mbrmPRimlEfSjplKGCShPVWjF6Pt9A=="
vapid_PRIVATE_KEY = "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgswSiYtHbjUBg4CHBpBE9vTx6CwCRFlvgQRR5hpjYnZ6hRANCAATQamIjmemtsyO/JeRaAI/jddkMGa4QI+XgT/Dd/vIkv6S48QWZthPvmr+ZuuY9GKaUR9KM+UoYJKE9VaMXo+30"

@app.route("/register",methods= ['POST','GET'])
def registerForm():
    if request.method == 'POST':
        name = request.form["personName"]
        number = request.form["phoneNumber"]
        email = request.form["personEmail"]
        password = request.form["password"]
        confirmPassword = request.form["confirmPassword"]
        duplicateEmail =  User.query.filter_by(email=email).first()

        if password != confirmPassword:
            return json.dumps({"passwordError": "Passwords Do Not Match! "}),403
        if  duplicateEmail is not None:
            return json.dumps({"duplicateEmailError": "E-mail Already Exists! Please sign in."}),409

        pw_hash = bcrypt.generate_password_hash(password).decode('utf-8')
        user = User(name = name,email = email,password = pw_hash,number = number)
        
        db.session.add(user)
        db.session.commit()
        return json.dumps({"message": "Successfully Registered"}),200


@app.route("/login",methods = ['POST','GET'])
def logInForm():
    if request.method == 'POST':
        email = request.form['personEmail']
        password = request.form['password']
        getPerson = User.query.filter_by(email=email).first()
        
    
        if getPerson != None:
            hash_pass = getPerson.password
        if getPerson and bcrypt.check_password_hash(hash_pass,password):
            login_user(getPerson)
            token = jwt.encode({'public_id': getPerson.id,'exp': datetime.datetime.utcNow() + datetime.timedelta(days=365)},app.config['SECRET_KEY'] )
            return jsonify({'token':token.decode('UTF-8')})
        
        return json.dumps({"errorMessage":"E-mail Does Not Exist or Password Is Incorrect"}),404


@app.route("/logout",'GET'])

def logout():
    return json.dumps({"logout": True})

def token_required(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        req_data = {}
        req_data['headers'] = dict(request.headers)
        token = req_data['headers']['Authorization']
        if token == "undefined":
            return jsonify({'message': 'Token is missing.'}),404
        try:
            data = jwt.decode(token,app.config['SECRET_KEY'])
            current_user = User.query.filter_by(id=data['public_id']).first()
        except:
            return jsonify({'message': 'token is invalid'}),401

        return f(current_user,*args,**kwargs)
    return decorator

@app.route("/reminders",methods =['POST','GET'])
@token_required
def createReminders(current_user):
    if request.method == 'POST':
        form = json.loads(request.data.decode('UTF-8'))
        date = form['reminderDate'].split("-")
        time = form['reminderTime'].split(":")
        dateAndTime = datetime.datetime(int(date[0]),int(date[1]),int(date[2]),int(time[0]),int(time[1]))
        text = form['reminderText']
        enableMobileNotification = True if form['enableMobileNotification'] is True else False
        enableDesktopNotification = True if form['enableDesktopNotification'] is True else False
        
        
        appointmentDate = datetime.datetime(int(date[0]),int(date[2]))
        getTodayDate =  datetime.datetime.today().strftime('%Y-%m-%d').split("-")
        todayDate = datetime.datetime(int(getTodayDate[0]),int(getTodayDate[1]),int(getTodayDate[2]))

        createReminder = Reminder(
            text=text,date = dateAndTime,notifyMobile = enableMobileNotification,notifyDesktop = enableDesktopNotification,numberOfDaysUntilAppointment = modules.cal_days_diff(appointmentDate,todayDate),person_id = current_user.id
        )
        db.session.add(createReminder)
        db.session.commit()
        return jsonify({"message": "Successfully Updated"}),200



@app.route("/notification",methods = ['POST'])
@token_required
def setNotifications(current_user):
    form = json.loads(request.data.decode('UTF-8'))
    subscription = form["subscription"]
    createNotif = Reminder(subscription = subscription)
    db.session.add(createNotif)
    db.session.commit()
    message = "Hello From Server"
    vapid_CLAims = {
        "sub": "my email"
    }

    try:
        modules.send_web_push(subscription,message,vapid_PRIVATE_KEY,vapid_CLAims)
        return jsonify({'success':1})
    except Exception as e:
        print("error",e)
        return jsonify({'Failed':str(e)})

提醒列表.jsx

import React,{useState,useRef} from "react";


import {Form,Button,Popover,OverlayTrigger} from "react-bootstrap";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons'

function ReminderLists(props) {

    const [isChecked,setChecked] = useState(false);
    const [changeInput,setChangeInput] = useState(props.text_value);
    const [storeFormData,setFormData] = useState({
        reminderText: "",reminderDate: "",reminderTime: "",enableMobileNotification: false,enableDesktopNotification:false,})
    const publicKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0GpiI5nprbMjvyXkWgCP43XZDBmuECPl4E/w3f7yJL+kuPEFmbYT75q/mbrmPRimlEfSjplKGCShPVWjF6Pt9A=="
  

    const header = {
        'Content-Type': 'application/json','Authorization': props.token,}
 



    function check(e) {
        const id_to_be_deleted = e.target.attributes.getNamedItem("unique_Key").value;
       
        if(!isChecked) {
            setChecked(true);
            props.addIds(isChecked,id_to_be_deleted);

        }

        else {
            setChecked(false);
            props.addIds(isChecked,id_to_be_deleted)
        }
    }

    function setChange(e) {
        setChangeInput(e.target.value);
        props.local_storage(e);
        storeFormData.reminderText=e.target.value
      
    }

    function urlB64ToUint8Array(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;
    }
    

    function handleSubmit(e) {

        console.log("Token in reminder list " + props.token)
        e.preventDefault();
        fetch('http://127.0.0.1:5000/reminders',{
          method: 'POST',headers:header,body: JSON.stringify(storeFormData)
        }).then(res=>res.json()).then(res=> {
        
            // console.log("Local storage is set")
            
            console.log(res.message);
            notify()
        })


        async function notify() {
            if ('serviceWorker' in navigator && 'PushManager' in window) {
                navigator.serviceWorker.register("/sw.js").then(serviceWorkerRegistration => {
                  console.log('Service worker was registered.');
                  console.log({serviceWorkerRegistration});
                }).catch(error => {
                  console.log('An error occurred while registering the service worker.');
                  console.log(error);
                });
              
              } else {
                console.log('browser does not support service workers or push messages.');
                return;
            }

            const result = await Notification.requestPermission();
            console.log("Permission " + result)
            if (result === 'denied') {
                console.log('The user explicitly denied the permission request.');
                return;
            }
            if (result === 'granted') {
                console.log('The user accepted the permission request.');

                const registration = await navigator.serviceWorker.getRegistration();
                const subscribed = await registration.pushManager.getSubscription();
                if (subscribed) {
                    console.log('User is already subscribed.');
                    return;
                }

              
          
                const subscription = await registration.pushManager.subscribe({
                    userVisibleOnly: true,applicationServerKey:  urlB64ToUint8Array(publicKey)
                   
                });

                fetch("http://127.0.0.1:5000/notification",{
                    method: "POST",body: JSON.stringify({"subscription":subscription})
                })
         
            }
        }

      

    }
    

    return ( 
        <Form>
            <fieldset>
                <div className = "input-group mb-3">
                    <div className="input-group-prepend">
                        <div className="input-group-text">
                            <input unique_Key = {props.id}   onInput = {e=>   e.target.checked = isChecked} onClick={e=> check(e) } checked = {props.checked} id = "check-item" type="checkBox" aria-label="CheckBox for following text input"/>
                        </div>
                    </div>
                    <textarea id = {props.id} onChange = {e=>setChange(e)} value = {changeInput}  class="form-control"  rows="1" name = "reminderText" ></textarea>
                    <input type="date" id="start" name="reminderDate" onChange = {(e)=> storeFormData.reminderDate=e.target.value}></input>
                    <input type="time" id="appt" name="reminderTime" min="09:00" max="18:00" required onChange = {(e)=> storeFormData.reminderTime=e.target.value}></input>


                    <OverlayTrigger
                    trigger="click"
                    key={'bottom'}
                    placement={'bottom'}
                    overlay={
                    <Popover id={`popover-positioned-${'bottom'}`}>
                        <Popover.Title as="h3">{`Notification Settings`}</Popover.Title>
                        <Popover.Content>
                     
                        <div>
                            <input  type="checkBox" id= "mobile" name="enableMobileNotification" value= "mobile" 
                            onChange = {(e)=> storeFormData.enableMobileNotification= !storeFormData.enableMobileNotification}>
                            </input>

                            <label className = "padding-left" for="mobile">Enable Mobile</label>
                        </div>

                        <div>
                            <input  type="checkBox" id="desktop" name="enableDesktopNotification" value="desktop"
                            onChange = {(e)=> storeFormData.enableDesktopNotification= !storeFormData.enableDesktopNotification}
                            >



                            </input>
                            <label className = "padding-left" for="desktop">Enable Desktop</label>
                        </div>
                        <Button variant="primary" size="sm" type="submit" onClick = {handleSubmit}>Submit</Button>
                 
                       
                        </Popover.Content>
                    </Popover>
                    }>

                    <Button className = "black app-btns " id="Popover1" type="button">
                        <FontAwesomeIcon icon = {faInfoCircle} size = "2x" />
                    </Button>
                    </OverlayTrigger>
                </div>
            </fieldset>
        </Form>



   
    )
}

export {ReminderLists};

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)