React Native应用无法连接Django Channels WebSocket的问题求助
Django Channels WebSocket在React Native中返回403拒绝,Web端正常连接
问题描述
我基于Django Channels搭建了WebSocket服务,HTTP视图可正常访问,但仅在React Native应用中WebSocket连接被拒绝,React Web应用则能完美运行。
React Native 移动端代码
// App.js 核心连接逻辑 var ws = React.useRef( new WebSocket('ws://192.168.10.14:8000/ws/chat/Hello/'), ).current; ws.onopen = () => { setServerState('Connected to the server'); }; ws.onclose = e => { setServerState('Disconnected. Check internet or server.'); }; ws.onerror = e => { console.error(e); setServerState(e.message); }; ws.onmessage = e => { serverMessagesList.push(e.data); setServerMessages([...serverMessagesList]); }; const submitMessage = () => { ws.send(messageText); setMessageText(''); setInputFieldEmpty(true); };
报错信息
ERROR {"isTrusted": false, "message": "Expected HTTP 101 response but was '403 Access denied'"}
React Web 端代码(可正常运行)
// App.js 核心连接逻辑 let W3CWebSocket = require("websocket").w3cwebsocket; var client = new W3CWebSocket("ws://192.168.10.14:8000/ws/chat/Hello/"); client.onerror = function (e) { console.log("Connection Error: " + JSON.stringify(e)); console.log("Connection Error"); }; client.onopen = function () { console.log("WebSocket Client Connected"); let data = JSON.stringify({ message: "Hello Socket!" }); client.send(data); }; client.onclose = function () { console.log("echo-protocol Client Closed"); }; client.onmessage = function (e) { if (typeof e.data === "string") { console.log("Received: '" + e.data + "'"); } };
后端配置
urls.py
websocket_urlpatterns = [ re_path(r'ws/chat/(?P<room_name>\w+)/$', consumer.ChatConsumer.as_asgi()), ]
Consumer.py
from asgiref.sync import async_to_sync import json from channels.generic.websocket import WebsocketConsumer 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 # 加入房间组 async_to_sync(self.channel_layer.group_add)( self.room_group_name, self.channel_name ) self.accept() def disconnect(self, close_code): print(close_code) # 离开房间组 async_to_sync(self.channel_layer.group_discard)( self.room_group_name, self.channel_name ) # 接收WebSocket消息 def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] # 发送消息到房间组 async_to_sync(self.channel_layer.group_send)( self.room_group_name, { 'type': 'chat_message', 'message': message } ) # 接收房间组消息 def chat_message(self, event): message = event['message'] # 发送消息到WebSocket self.send(text_data=json.dumps({ 'message': message }))
settings.py
ASGI_APPLICATION = "xyz.asgi.application" CHANNEL_LAYERS = { 'default': { 'BACKEND': "channels.layers.InMemoryChannelLayer", 'hosts': [('localhost')], } }
asgi.py
""" ASGI config for XYZ project. """ import Appointments import os from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from channels.security.websocket import AllowedHostsOriginValidator from django.core.asgi import get_asgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'XYZ.settings') django_asgi_app = get_asgi_application() application = ProtocolTypeRouter({ "http": django_asgi_app, "websocket": AllowedHostsOriginValidator( AuthMiddlewareStack( URLRouter( Appointments.urls.websocket_urlpatterns ) ) ), })
解决方案
1. 排查Origin验证拦截
React Native的WebSocket请求不会携带浏览器标准的Origin头,或Origin值不在Django的ALLOWED_HOSTS列表中,导致AllowedHostsOriginValidator返回403。
- 临时测试:修改
asgi.py,暂时移除AllowedHostsOriginValidatorapplication = ProtocolTypeRouter({ "http": django_asgi_app, "websocket": AuthMiddlewareStack( URLRouter( Appointments.urls.websocket_urlpatterns ) ), }) - 正式配置:开发环境可允许所有Origin,生产环境需指定React Native的调试/生产Origin(如
exp://192.168.10.14:19000)
2. 处理认证中间件限制
AuthMiddlewareStack要求请求携带认证信息(如Session Cookie),但React Native默认不会自动携带Cookie。
- 方案一:携带Token参数
在React Native中通过URL参数传递认证Token:
在Consumer中验证Token:const authToken = '用户认证Token'; var ws = React.useRef( new WebSocket(`ws://192.168.10.14:8000/ws/chat/Hello/?token=${authToken}`), ).current;def connect(self): token = self.scope['query_params'].get('token') from rest_framework.authtoken.models import Token try: user = Token.objects.get(key=token).user self.scope['user'] = user except Token.DoesNotExist: self.close() return # 后续原逻辑... - 方案二:移除认证要求
如果WebSocket无需用户认证,可将AuthMiddlewareStack替换为SessionMiddlewareStack(仅建议开发环境使用)。
3. 确认网络连通性
确保React Native设备与Django服务器在同一局域网内,192.168.10.14可被设备访问,服务器防火墙未拦截8000端口。
内容的提问来源于stack exchange,提问作者usamayaseen
相关产品推荐
相关产品推荐

