我正在尝试使用
py-vapid
、
pywebpush
和
django-push-notifications
通过 Webpush 发送通知。当我尝试从 django 管理网站发送测试通知时,我在控制台中收到此回溯日志:
| Internal Server Error: /djangoadmin/push_notifications/webpushdevice/
| Traceback (most recent call last):
| File "/usr/local/lib/python3.8/site-packages/asgiref/sync.py", line 518, in thread_handler
| raise exc_info[1]
| File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 38, in inner
| response = await get_response(request)
| File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
| response = await wrapped_callback(request, *callback_args, **callback_kwargs)
| File "/usr/local/lib/python3.8/site-packages/asgiref/sync.py", line 468, in __call__
| ret = await asyncio.shield(exec_coro)
| File "/usr/local/lib/python3.8/site-packages/asgiref/current_thread_executor.py", line 40, in run
| result = self.fn(*self.args, **self.kwargs)
| File "/usr/local/lib/python3.8/site-packages/asgiref/sync.py", line 522, in thread_handler
| return func(*args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 616, in wrapper
| return self.admin_site.admin_view(view)(*args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
| response = view_func(request, *args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
| response = view_func(request, *args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 232, in inner
| return view(request, *args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 43, in _wrapper
| return bound_method(*args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 130, in _wrapped_view
| response = view_func(request, *args, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1723, in changelist_view
| response = self.response_action(request, queryset=cl.get_queryset(request))
| File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1408, in response_action
| response = func(self, request, queryset)
| File "/usr/local/lib/python3.8/site-packages/push_notifications/admin.py", line 109, in send_message
| self.send_messages(request, queryset)
| File "/usr/local/lib/python3.8/site-packages/push_notifications/admin.py", line 38, in send_messages
| r = device.send_message("Test single notification")
| File "/usr/local/lib/python3.8/site-packages/push_notifications/models.py", line 270, in send_message
| return webpush_send_message(self, message, **kwargs)
| File "/usr/local/lib/python3.8/site-packages/push_notifications/webpush.py", line 35, in webpush_send_message
| response = webpush(
| File "/usr/local/lib/python3.8/site-packages/pywebpush/__init__.py", line 560, in webpush
| vv = Vapid.from_string(private_key=vapid_private_key)
| File "/usr/local/lib/python3.8/site-packages/py_vapid/__init__.py", line 144, in from_string
| key = b64urldecode(pkey)
| File "/usr/local/lib/python3.8/site-packages/py_vapid/utils.py", line 14, in b64urldecode
| return base64.urlsafe_b64decode(data + b"===="[len(data) % 4:])
| File "/usr/local/lib/python3.8/base64.py", line 133, in urlsafe_b64decode
| return b64decode(s)
| File "/usr/local/lib/python3.8/base64.py", line 87, in b64decode
| return binascii.a2b_base64(s)
| binascii.Error: Invalid base64-encoded string: number of data characters (41) cannot be 1 more than a multiple of 4
它似乎说我的密钥没有采用有效的格式来转换为 Base64,但我检查了 pywebpush文档和我的密钥格式正确。它们是用
VAPID EC2 private key PEM file
生成的,如下所示:
py-vapid
以下是有问题的测试密钥:
import os
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, PublicFormat
from py_vapid import Vapid
import base64
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Generate VAPID key pair
vapid = Vapid()
vapid.generate_keys()
# Get public and private keys for the vapid key pair
vapid.save_public_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "public_key.pem"))
public_key_bytes = vapid.public_key.public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)
vapid.save_key(os.path.join(PROJECT_ROOT, "keys", "webpush", "private_key.pem"))
# Convert the public key to applicationServerKey format
application_server_key = base64.urlsafe_b64encode(public_key_bytes).replace(b'=', b'').decode('utf8')
with open(os.path.join(PROJECT_ROOT, "keys", "webpush", "ApplicationServerKey.key"), "w") as f:
f.write(application_server_key)
我尝试使用 OpenSSL 手动生成密钥,但它仍然无法工作。
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgFCZ0WxsNENwKK3Pf
c0HFZPDlr/KAmjIwB6Hz/OdH/YKhRANCAASFpOW98Q4xfCjD0Taog9ZstRQgS+Ch
L7HoOBGHFZAQwpEd83Qt58bnUCIZFwMZc4tyHKV+b0UxM2cMzm8pMI4z
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhaTlvfEOMXwow9E2qIPWbLUUIEvg
oS+x6DgRhxWQEMKRHfN0LefG51AiGRcDGXOLchylfm9FMTNnDM5vKTCOMw==
-----END PUBLIC KEY-----
I've tried to generate keys manually using OpenSSL but it still won't work.
错误信息 "binascii.Error: Invalid base64-encoded string: number of data characters (41) cannot be 1 more than a multiple of 4" 表明你正试图将一个无效的 Base64 字符串解码。问题并非出在你的密钥格式,而是出在你如何读取或使用密钥。
看起来你在代码中并没有直接使用私钥进行 Base64 解码。
py_vapid
库应该在内部处理这个过程。问题可能出现在以下地方:
-
错误地读取私钥:
确保你正确地从文件中读取私钥,并且没有引入额外的空格或字符。使用
open()
函数时,最好使用'rb'
模式以二进制格式读取文件,避免潜在的编码问题:
with open(os.path.join(PROJECT_ROOT, "keys", "webpush", "private_key.pem"), "rb") as f:
private_key = f.read()
# ... 然后使用 private_key 字符串
-
vapid_private_key
变量的值不正确: 确认你将读取的私钥内容正确地传递给了webpush()
函数中的vapid_private_key
参数。 打印vapid_private_key
的值,确保它包含正确的私钥字符串,包括 "-----BEGIN PRIVATE KEY-----" 和 "-----END PRIVATE KEY-----" 部分。 -
django-push-notifications
配置问题: 检查django-push-notifications
的设置,确保你正确地配置了 VAPID 密钥路径或变量。
调试建议:
-
打印
pkey
的值: 在py_vapid/__init__.py
文件的from_string
函数中,添加一行代码打印pkey
的值,看看它是否是预期的私钥字符串:
def from_string(cls, pkey):
print("pkey:", pkey) # 添加这行
key = b64urldecode(pkey)
# ...
-
检查
django-push-notifications
设置: 仔细检查settings.py
文件或其他相关配置文件,确保你正确配置了 VAPID 密钥路径或变量。 -
使用调试器逐步执行代码: 使用调试器可以帮助你逐行检查代码,观察变量的值,并确定问题的确切位置。
如果以上步骤都不能解决问题,请提供以下信息:
-
你是如何调用
webpush()
函数的?请分享相关代码片段。 -
django-push-notifications
的版本号。 -
你是如何配置
django-push-notifications
的 VAPID 密钥设置的?
通过提供更多信息,我可以更好地帮助你解决问题。
标签:python,django,base64,web-push,django-push-notifications From: 78791129