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

Django Channels WebSocket路由报No route found for path错误排查

问题根因

路由报错的直接原因是前后端WebSocket请求路径不匹配,另外还有两处隐藏问题会导致功能运行异常:

  • 后端路由表仅注册了/function_images/ws/progress、/analysis_generator/ws/progress两个带应用前缀的路径,但前端所有页面都固定请求/ws/progress/,该路径未在路由表中注册,自然匹配失败抛出No route found错误。
  • 后端路由正则未加路径起止锚点,也没有兼容末尾斜杠规则,就算路径前缀正确,前端带末尾斜杠的请求也可能出现匹配异常。
  • 你在connect方法中直接执行带time.sleep的同步阻塞死循环,会占用Channels的工作线程,就算路由匹配成功,后续WebSocket连接也会卡死,甚至影响其他正常请求。
修正方案

1. 修正前端WebSocket请求路径

根据当前访问的页面自动拼接对应应用前缀的WS地址,不要写死统一路径:

const establishSocketConnection = () => {
    // 自动提取当前页面的应用前缀,比如在/function_images/页面下提取到的前缀为function_images
    const pathPrefix = window.location.pathname.split('/')[1];
    const socket_url = `ws://${window.location.host}/${pathPrefix}/ws/progress/`;
    let socket = new WebSocket(socket_url);

    socket.onmessage = (event) => {
        const data = JSON.parse(event.data);
        if (data.type != "progress") {
            return;
        }
        const progress = +data.message;
        console.log(`Progress: ${progress}`);
        updateProgressBar(progress);
    }

    socket.onclose = (event) => {
        console.log("Socket connection closed, close code:", event.code);
    }

    socket.onerror = (error) => {
        console.log("Socket error: ", error);
    }

    return socket;
}

2. 修正后端路由正则规则

给路径加上起止锚点,兼容末尾斜杠写法,避免匹配歧义:

from django.urls import re_path

from function_images.consumers import FunctionImagesProgressConsumer
from analysis_generator.consumers import AnalysisProgressConsumer

websocket_urlpatterns = [
    re_path(r"^function_images/ws/progress/?$", FunctionImagesProgressConsumer.as_asgi()),
    re_path(r"^analysis_generator/ws/progress/?$", AnalysisProgressConsumer.as_asgi()),
]

正则中^标记路径起始位置,$标记路径结束位置,/?表示路径末尾可以携带0个或1个斜杠,完美兼容前端带斜杠的请求写法。

3. 修复Consumer阻塞问题

将阻塞式的进度轮询逻辑放到独立守护线程中执行,避免卡住Channels的主工作线程:

import threading
import time
import json
import re
from channels.generic.websocket import WebsocketConsumer

class ProgressConsumer(WebsocketConsumer):
    max_anims = None
    
    def connect(self):
        self.log_cache = ""
        print("Websocket connected.")
        if not self.max_anims:
            # 未自定义NotSetError的话直接用内置ValueError即可
            raise ValueError("max_anims not set")
        self.room_group_name = "progress"
        self.accept()
        # 阻塞逻辑放到独立线程运行,设置daemon=True保证主进程退出时线程自动回收
        threading.Thread(target=self.start_progress_update, daemon=True).start()

    def start_progress_update(self):
        cached_progress = 0
        progress = 0
        while progress != 100.0:
            time.sleep(1)
            updates = self.get_log_updates()
            if updates == "":
                continue
            if "Error" in updates:
                self.send(json.dumps({"error": updates}))
                self.clean_log()
                self.close(3000)
                return
            progress = self.calculate_progress(updates)
            if progress == cached_progress:
                continue
            self.send(json.dumps({
                'type': 'progress',
                'message': progress,
            }))
            cached_progress = progress

    def disconnect(self, close_code):
        print("Websocket disconnected. Code: ", close_code)

    def get_log_updates(self) -> str:
        if self.log_cache == self.get_log_cache():
            return ""
        s1 = set(self.log_cache.split("\n"))
        s2 = set(self.get_log_cache().split("\n"))
        self.log_cache = self.get_log_cache()
        return str(s1.symmetric_difference(s2))

    def calculate_progress(self, difference: str) -> float:
        if not "Animation" in difference:
            return 0.0
        animation_id = float(re.search("Animation (\d+)", difference).group(1))
        return ((animation_id + 1) / self.max_anims) * 100.0

    def clean_log(self):
        raise NotImplementedError("clean_log not implemented")
    
    def get_log_cache(self) -> str:
        raise NotImplementedError("get_log_cache not implemented")

两个子类消费者的代码不需要修改,保持原有逻辑即可。
所有修改完成后重启Django服务,清空浏览器缓存重新测试,WebSocket即可正常连接、推送进度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:30:47