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

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,暂时移除AllowedHostsOriginValidator
    application = 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:
    const authToken = '用户认证Token';
    var ws = React.useRef(
      new WebSocket(`ws://192.168.10.14:8000/ws/chat/Hello/?token=${authToken}`),
    ).current;
    
    在Consumer中验证Token:
    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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:15:31