Django与Flutter WebSocket连接失败问题求助
Django + Flutter WebSocket连接失败问题排查与解决
核心问题
Django后端通过Channels实现WebSocket服务,Flutter前端连接时返回404错误,握手无法升级为WebSocket协议。
现有代码与配置
Django端
1. Message模型
class Message(models.Model): room = models.ForeignKey(Room, on_delete=models.CASCADE) sender = models.ForeignKey(User, on_delete=models.CASCADE) content = models.TextField() timestamp = models.DateTimeField(auto_now_add=True) def __str__(self): return self.content
2. Consumers代码
class ChatConsumer(WebsocketConsumer): def connect(self): self.room_name = self.scope['url_route']['kwargs']['room_name'] self.room_group_name = 'chat_%s' % self.room_name # Join room group self.channel_layer.group_add( self.room_group_name, self.channel_name ) self.accept() def disconnect(self, close_code): # Leave room group self.channel_layer.group_discard( self.room_group_name, self.channel_name )
3. Routing配置(chat_app/routing.py)
websocket_urlpatterns = [ re_path(r'ws/chat_app/(?P<room_name>\w+)/$', ChatConsumer.as_asgi()), ]
4. 项目URL配置
urlpatterns = [ path('admin/', admin.site.urls), ..., path('ws/', include(websocket_urlpatterns)), ]
5. ASGI配置
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": OriginValidator( AuthMiddlewareStack( URLRouter( websocket_urlpatterns ), ['*'] ) ), })
6. CORS配置
INSTALLED_APPS = [ # other installed apps 'corsheaders', ] CORS_ALLOW_ALL_ORIGINS = True ALLOWED_HOSTS = ['*']
Flutter端连接代码
class ChatScreen extends StatefulWidget { const ChatScreen({ Key? key, required this.room, }) : super(key: key); final RoomModelResponse room; @override _ChatScreenState createState() => _ChatScreenState(); } class _ChatScreenState extends State<ChatScreen> { final TextEditingController _controller = TextEditingController(); final List<String> _messages = []; late WebSocketChannel _channel; @override void initState() { super.initState(); _channel = IOWebSocketChannel.connect( 'wss://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/'); _channel.stream.listen((message) { setState(() { _messages.add(message); }); }); } }
错误信息
Flutter终端报错
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to 'http://192.168.0.11:8000/ws/chat_app/3wVCio/#' was not upgraded to websocket #0 new IOWebSocketChannel._withoutSocket.<anonymous closure> (package:web_socket_channel/io.dart:119:24) #1 Stream.handleError.<anonymous closure> (dart:async/stream.dart:931:16) #2 _HandleErrorStream._handleError (dart:async/stream_pipe.dart:269:17) #3 _ForwardingStreamSubscription._handleError (dart:async/stream_pipe.dart:157:13) #4 _RootZone.runBinaryGuarded (dart:async/zone.dart:1606:10) #5 _BufferingStreamSubscription._sendError.sendError (dart:async/stream_impl.dart:358:15) #6 _BufferingStreamSubscription._sendError (dart:async/stream_impl.dart:376:7) #7 _BufferingStreamSubscription._addError (dart:async/stream_impl.dart:280:7) #8 _SyncStreamControllerDispatch._sendError (dart:async/stream_controller.dart:788:19) #9 <…>
Django日志
Not Found: /ws/chat_app/3wVCio/ [15/Feb/2024 16:46:19] "GET /ws/chat_app/3wVCio/ HTTP/1.1" 404 4379
Postman测试结果
Error: Unexpected server response: 404 Handshake Details Request URL: http://192.168.0.11:8000/ws/chat_app/3wVCio/ Request Method: GET Status Code: 404 Not Found Request Headers Sec-WebSocket-Version: 13 Sec-WebSocket-Key: GW/3ZvtVDOXDlKNkIwg2zw== Connection: Upgrade Upgrade: websocket Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Host: 192.168.0.11:8000 Response Headers Date: Fri, 16 Feb 2024 15:28:45 GMT Server: WSGIServer/0.2 CPython/3.12.1 Content-Type: text/html; charset=utf-8 X-Frame-Options: DENY Content-Length: 4379 X-Content-Type-Options: nosniff Referrer-Policy: same-origin Cross-Origin-Opener-Policy: same-origin
解决方案
1. 修复路由重复问题
当前路由配置存在路径重复:websocket_urlpatterns中已包含ws/chat_app/前缀,项目URL又添加了ws/前缀,导致实际匹配路径为/ws/ws/chat_app/xxx/,但请求路径是/ws/chat_app/xxx/,因此返回404。
修改chat_app/routing.py:
websocket_urlpatterns = [ re_path(r'chat_app/(?P<room_name>\w+)/$', ChatConsumer.as_asgi()), ]
项目URL配置保持不变,此时正确的请求路径为/ws/chat_app/xxx/,与前端请求一致。
2. 修复ASGI配置中的OriginValidator参数错误
OriginValidator的允许源参数位置错误,需调整为:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": OriginValidator( AuthMiddlewareStack( URLRouter(websocket_urlpatterns) ), allowed_origins=['*'] # 此参数属于OriginValidator,而非AuthMiddlewareStack ), })
3. Flutter端使用正确的WebSocket协议
Django开发服务器默认未配置SSL,需将wss://改为ws://:
_channel = IOWebSocketChannel.connect( 'ws://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/');
4. 确认Channels核心配置
确保settings.py中已正确配置Channels:
INSTALLED_APPS = [ ..., 'channels', 'chat_app', 'corsheaders', ] # 开发环境使用内存通道层,生产环境建议替换为Redis CHANNEL_LAYERS = { "default": { "BACKEND": "channels.layers.InMemoryChannelLayer", }, } # 指定ASGI应用入口 ASGI_APPLICATION = "project.asgi.application"
5. 适配房间ID的正则匹配
如果房间ID包含\w(字母、数字、下划线)之外的字符,需修改路由正则为:
re_path(r'chat_app/(?P<room_name>[^/]+)/$', ChatConsumer.as_asgi()),
此正则会匹配除斜杠外的所有字符,兼容更多格式的房间ID。
验证步骤
- 重启Django开发服务器
- 用Postman测试WebSocket连接,URL为
ws://192.168.0.11:8000/ws/chat_app/3wVCio/ - 运行Flutter应用,重新尝试连接
内容的提问来源于stack exchange,提问作者Geo48
相关产品推荐
相关产品推荐

