Django Channels 无法从WebSocket握手(HTTP升级请求)中获取Cookie
针对你当前使用django==3.1.5、channels==3.0.3版本下,浏览器已确认发送Cookie但ASGI scope中不存在cookie请求头的问题,按以下链路逐一排查即可定位问题:
第一步:先明确丢头的发生位置
不要直接在你重写的Cookie解析逻辑里打日志,第一时间在整个中间件栈的最外层加载调试逻辑,拿到ASGI服务器传入的原始scope内容,直接打印所有请求头:
# asgi.py 文件内的测试中间件,放在所有中间件最外层 class RawScopeDebugMiddleware: def __init__(self, inner_app): self.inner_app = inner_app async def __call__(self, scope, receive, send): # 仅打印WebSocket类型的scope,过滤HTTP请求干扰 if scope.get("type") == "websocket": raw_headers = {h[0].decode(): h[1].decode() for h in scope.get("headers", [])} print("ASGI入口原始请求头:", raw_headers) await self.inner_app(scope, receive, send)
- 注意ASGI规范要求所有请求头的键统一为小写二进制格式,不存在大小写匹配的问题,只要头传进来了,一定能匹配到
b"cookie"的键。 - 如果这一层打印的原始头里就没有
cookie字段,说明问题出在ASGI服务器到应用入口的链路,和你写的Cookie解析逻辑、中间件栈顺序没有任何关系。 - 如果这一层打印的原始头里有
cookie字段,但走到你自定义解析逻辑的时候没了,问题出在后续的中间件栈里,需要逐层往前找哪个中间件做了头过滤。
第二步:排查链路中会主动剥离Cookie头的节点
- ASGI服务器侧检查:确认你使用的daphne/uvicorn启动配置没有开启头过滤规则。Channels3.0.3配套的daphne 3.0.x版本在部分环境下处理WS升级请求时,会因为二进制头的解析顺序问题,漏掉cookie类型的请求头,可以尝试将daphne升级到3.0.2以上的小版本,或者直接切换uvicorn>=0.20.0版本作为ASGI服务器做对比测试。
- 反向代理/网关侧检查:如果你的WS请求是经过Nginx、云网关转发到应用的,需要确认WS升级配置里开启了请求头全量透传。很多网关默认对WS请求的敏感头(Cookie、Authorization)做安全过滤,没有手动配置透传规则的情况下,会直接把Cookie头从请求里删掉,到应用层的时候已经不存在了。
- 中间件栈顺序检查:如果原始入口的scope里是有cookie头的,检查栈里的跨域处理中间件、鉴权中间件:部分自定义跨域组件会做白名单头校验,不在白名单里的请求头会被直接遍历删除,需要把
cookie加入头白名单,或者把CookieMiddleware放在跨域中间件之前加载。
第三步:排查浏览器实际发送的Cookie有效性
你在Chrome开发者工具里看到的Cookie,未必是WS握手请求实际携带的Cookie,需要重点核对:
- 找到WS握手对应的101状态码请求,打开「已发送的请求头」面板,确认
Cookie字段是真实存在于请求头列表里,不要和「应用存储的Cookie列表」搞混——很多场景下你能看到本地存储的Cookie,但因为属性不匹配,浏览器根本不会在WS请求里携带。 - 核对Cookie的三个核心属性:
SameSite:默认值为Lax的Cookie,在跨站WS请求中不会被携带;如果你的WS连接地址和前端页面的域名存在跨站差异,需要把Cookie的SameSite设为None,同时配套开启Secure属性才能被浏览器携带。Domain:如果Cookie设置的域名和WS请求的域名不匹配(比如Cookie绑的是a.example.com,WS请求走的是b.example.com),且没有设置泛域名匹配,浏览器不会携带该Cookie。Path:如果Cookie的Path设置为/admin,但WS请求的路径是/ws/chat,浏览器也不会携带该Cookie。
- 本地开发场景下如果存在端口差异(比如前端跑在5173端口,WS连的是8000端口),需要确认浏览器对该端口的Cookie存储是按源匹配的,避免因为端口差异导致Cookie不被携带。
常见问题的快速解决
- 不要依赖Channels内置的
CookieMiddleware手动从头解析Cookie,Channels3.x版本本身是支持自动把请求头里的cookie字段解析到scope["cookies"]的,只要头能正常传到应用层,不需要自己重写解析逻辑。 - 如果是本地开发跨域场景下的WS连接,建议直接把前后端、WS服务绑定在同一个域名的同一个端口下,通过反向代理把不同路径的请求转发到对应服务,从根源上避免跨域导致的Cookie携带问题。
内容的提问来源于stack exchange,提问作者ByteBat
相关产品推荐
相关产品推荐

