【发布时间】:2021-09-10 05:51:12
【问题描述】:
TL;DR
升级到 Django 3.2 后,使用不推荐使用的 Channels 方法进行 ASGI 处理工作。使用新的推荐方法不起作用。
我正在从 Django 3.0/Channels 2 升级到 Django 3.2/Channels 3。
在频道 3.0 release notes 中,声明不推荐使用不带 http 键的 ProtocolRouter 实例化,并且应该使用 django.core.asgi.get_asgi_application 作为值。
然而,当我使用 get_asgi_application 明确使用 http 协议时,我的中间件不再工作:应用程序抱怨我在异步中使用同步中间件语境。这是弹出的Django错误:
SynchronousOnlyOperation at /graphql/
You cannot call this from an async context - use a thread or sync_to_async.
...
完整的追溯在这里:https://pastebin.com/chRyW4VL
这里是asgi.py的内容
# my_project/asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
import django
from django.core.asgi import get_asgi_application
assert os.environ.get('DJANGO_SETTINGS_MODULE') is not None, \
'The `DJANGO_SETTINGS_MODULE` env var must be set.'
django.setup()
from core.urls import ws_routes
application = ProtocolTypeRouter({
# If the following line is not commented out, I get the above error.
# 'http': get_asgi_application(),
'websocket': URLRouter(ws_routes)
})
[编辑] 这是导致问题的中间件的 sn-p:
# core/middleware.py
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
...
response = self.get_response(request) # THIS LINE CAUSES THE ERROR
...
return response
# Down the traceback, the culprit is a database call:
# core/**/another_module.py
def get_user_by_id(uid):
return User.objects.get(id=uid) # BOOM!
"""
I know this db call is synchronous, but this is fine:
I don't want it to be something else. I only want to
use it in standard HTTP request/response cycle, with synchronous views, etc.
"""
我不想在我的 HTTP 处理程序/中间件中使用异步逻辑,因为我更喜欢同步模式的简单性。我只使用 Channels 来处理 websockets。
我正在寻求有关如何遵循频道指南的建议(即明确说明 http 协议应用程序)。
同时,我只是忽略弃用警告,并使用 Channels 提供的 ASGI 处理程序。
【问题讨论】:
-
这很有趣。您是否使用 Daphne 来同时处理 WebSocket 和正常请求?您能否还显示导致问题的中间件?快速浏览源代码会发现 Django 应该使任何中间件适应“正确”模式,所以问题可能出在中间件本身
-
确实,这两种情况都使用了达芙妮。我编辑了我的原始帖子以共享导致问题的中间件:它只是将当前用户存储在一个上下文变量中,可供整个应用程序使用。
-
能否包含回溯?如果有问题的行是
self.get_response,它似乎与这个确切的中间件无关。如果删除此中间件,错误会消失吗? -
请查看我更新的帖子,了解有关回溯的更多信息。是的,删除此中间件后错误消失。
-
谢谢,不幸的是,我还是不明白。由于错误发生在
self.get_response上,这意味着它与此中间件无关,但是如果您删除它,错误就会消失
标签: django django-channels asgi