如何解决通过 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 举报,一经查实,本站将立刻删除。