You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Django Channels向React前端返回长轮询响应异常问题?

Django Channels长轮询响应延迟及Axios接收异常问题解决

我正在用Django Channels给React前端+Django REST后端实现长轮询,选用AsyncHttpConsumer(场景不支持WebSocket)。目前核心问题是:Consumer返回的响应无法立即到达前端,必须等Consumer再次发送响应,之前的或两次响应才会一起出现。

更新:发现问题与axios.get(...)请求相关,替换为fetch(...)后每次都能正常接收响应,但Axios平均每隔一次才能收到响应,暂未明确原因。


相关配置与代码

Asgi.py配置

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
django_asgi_app = get_asgi_application()

application = ProtocolTypeRouter(
    {
        "http": URLRouter(
            longpoll_urlpatterns + [re_path(r"", django_asgi_app)]
        ),
    }
)

Routing.py配置

longpoll_urlpatterns = [
    # 尝试过re_path但未生效
    path("analysisSubscription/<int:analysisId>/", consumers.AnalysisConsumer.as_asgi()),
]

Consumers.py实现

class AnalysisConsumer(AsyncHttpConsumer):
    async def handle(self, body):
        print("In Handle")
        print(self.scope)
        self.analysisId = self.scope["url_route"]["kwargs"]["analysisId"]
        self.analysis_group_name = f"analysis_{self.analysisId}"

        # 注册到对应频道组
        await self.channel_layer.group_add(self.analysis_group_name, self.channel_name)
        
        await self.send_headers(headers=[
            (b"Content-type", b"application/json"),
            (b"Access-Control-Allow-Origin", b"*"),
            (b"Access-Control-Allow-Headers", b"Origin, X-Requested-With, Content-Type, Accept, Authorization"),])
                
        # 必须先发送空body才能触发服务器发送headers
        await self.send_body(b"", more_body=True)

        print("Registered consumer for ID: ", self.analysisId, " and group: ", self.analysis_group_name)

       # await self.channel_layer.group_send(self.analysis_group_name, {"type": "analysis.update", "text": self.analysisId})

    async def http_request(self, message):
        print("In Request")
        print(message)
        if "body" in message:
            self.body.append(message["body"])
        if not message.get("more_body"):
            try:
                await self.handle(b"".join(self.body))
            except:
                print("Stopping")
                # 出错则断开连接,父类方法会直接断开导致长轮询失效
                await self.disconnect()
                raise StopConsumer()

    async def disconnect(self):
        print("Disconnecting!")
        await self.channel_layer.group_discard(self.analysis_group_name, self.channel_name)
    
    async def analysis_update(self, event):
        print(event)
        print("Inside Analysis Consumer")
        analysisId = event['id']
        analysisData = ""

        try:
            analysisData = await self.getAnalysis(analysisId)
            analysisData = json.dumps(analysisData)
        except Exception as ex:
            print(f"Failed to retrieve Analysis object: {ex}")
            return

        print("Retrieved analysis:\n\t", analysisData)
        await self.send_body(analysisData.encode('utf-8'))
        print("Sent the response")

        await asyncio.sleep(1)

        await self.http_disconnect(None)

    @database_sync_to_async
    def getAnalysis(self, id):
        return AnalysisSerializer(Analysis.objects.filter(id=id)[0]).data

Views.py触发更新代码

async_to_sync(layers.group_send)(f"analysis_{idAnalysis}", {"type": "analysis.update", "id": idAnalysis})

前端React请求代码

await axios.get(ApiUrl.analysisSubscribe(analysisId), {
            timeout: 60000,
        })

问题解决思路

1. 修复Consumer响应延迟问题

  • 明确响应结束标记:在analysis_update中发送响应时,需明确设置more_body=False,告知服务器响应已完成,立即推送给前端:
    # 替换原send_body调用
    await self.send_body(analysisData.encode('utf-8'), more_body=False)
    
  • 移除不必要的延迟:删除await asyncio.sleep(1),发送完响应后直接调用await self.http_disconnect(None),避免无意义等待。
  • 修正频道组移除方法:group_discard已废弃,改用group_remove:
    async def disconnect(self):
        print("Disconnecting!")
        await self.channel_layer.group_remove(self.analysis_group_name, self.channel_name)
    

2. 修复Axios接收异常问题

  • 禁用GET请求缓存:Axios默认缓存GET请求,添加时间戳参数避免缓存:
    await axios.get(ApiUrl.analysisSubscribe(analysisId), {
        timeout: 60000,
        params: {
            _: Date.now() // 随机参数禁用缓存
        }
    })
    
  • 明确响应类型:指定responseType确保Axios正确解析响应:
    await axios.get(ApiUrl.analysisSubscribe(analysisId), {
        timeout: 60000,
        responseType: 'json',
        params: { _: Date.now() }
    })
    

3. 其他优化点

  • 初始化请求body:在http_request开头初始化self.body,避免未定义报错:
    async def http_request(self, message):
        print("In Request")
        print(message)
        if not hasattr(self, 'body'):
            self.body = []
        if "body" in message:
            self.body.append(message["body"])
        # ... 后续代码
    
  • 缩小异常捕获范围:将except:改为捕获具体异常,避免误吞错误导致调试困难。

内容的提问来源于stack exchange,提问作者Doug Steiert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 10:55:55