我有一个正在使用 websockets 的现有 Django Channels 设置,我必须添加另一个端点来支持 SSE。我按照这里的示例https://channels.readthedocs.io/en/stable/topics/consumers.html使用
AsyncHttpConsumer
设置消费者,但我收到了错误:
TypeError: ServerSentEventsConsumer() missing 2 required positional arguments: 'receive' and 'send'
我的设置如下:
playground/consumers.py
from datetime import datetime
from channels.generic.http import AsyncHttpConsumer
class ServerSentEventsConsumer(AsyncHttpConsumer):
async def handle(self, body):
await self.send_headers(headers=[
(b"Cache-Control", b"no-cache"),
(b"Content-Type", b"text/event-stream"),
(b"Transfer-Encoding", b"chunked"),
])
while True:
payload = "data: %s\n\n" % datetime.now().isoformat()
await self.send_body(payload.encode("utf-8"), more_body=True)
await asyncio.sleep(1)
playground/asgi.py
import os
import django
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'playground.settings.production')
django.setup()
application = get_asgi_application()
playground/routing.py
from playground.asgi import application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from .consumers import (
BaseConsumer,
ServerSentEventsConsumer,
)
from django.urls import path, re_path
application = ProtocolTypeRouter(
{
"http": application,
"websocket": AllowedHostsOriginValidator(
JwtAuthMiddlewareStack(
URLRouter(
[
re_path(r"^wss$", BaseConsumer),
re_path("sse", ServerSentEventsConsumer.as_asgi()) # <- Desperate attempt. I don't wanna use websockets.
]
)
)
),
}
)
playground/urls.py
urlpatterns = [
path("sse/", ServerSentEventsConsumer.as_asgi(), name="sse")
]
我使用以下软件版本:
asgiref = "3.7.2"
Django = "4.0.10"
channels-redis = "4.1.0"
channels = "4.0.0"
我见过一些相关问题,人们通过将 Channels 降级到版本 3 来解决这些问题。这对我来说不是一个选择,因为首先要升级到 Django 4 是团队的主要工作。
任何意见都将受到高度赞赏。
更新#1
我尝试将
Channels
降级到较低版本,但仍然遇到相同的错误:
asgiref = "3.7.2"
channels = "3.0.5"
channels-redis = "3.4.1"
daphne = "3.0.2"
我最终通过进行以下更改成功地完成了这项工作:
playground/routing.py
from playground.asgi import application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from .consumers import (
BaseConsumer,
ServerSentEventsConsumer,
)
from django.urls import path, re_path
application = ProtocolTypeRouter(
{
- "http": application, # <-- removed this
+ "http": URLRouter([
+ path("sse/<str:username>": ServerSentEventsConsumer.as_asgi()),
+ path(r"", application),
+ ]),
"websocket": AllowedHostsOriginValidator(
JwtAuthMiddlewareStack(
URLRouter(
[
re_path(r"^wss$", BaseConsumer)
]
)
)
),
}
)