必须配置 Nginx 透传 HTTPS 协议头并启用 Django 的 SECURE_PROXY_SSL_HEADER,否则 SESSION_COOKIE_SECURE=True 会导致 Cookie 不被设置;因 Django 收到的是 HTTP 请求,无法识别外部 HTTPS,从而静默跳过写入 sessionid。

因为 Django 4.2 默认启用 SAMESITE=Lax,而 Nginx 反向代理时若未透传 HTTPS 头、或前端域名与后端不一致,会导致浏览器拒绝发送 Session Cookie,从而“丢 session”。
为什么 SESSION_COOKIE_SECURE=True 在 Nginx 下必须配合真实 HTTPS
Django 4.2+ 要求:当 SESSION_COOKIE_SECURE=True 时,只有在 HTTPS 请求中才会设置和发送 Cookie。但很多部署场景里,Nginx 是 HTTPS 终结点(即用户走 HTTPS 访问 Nginx,Nginx 再以 HTTP 转发给 Django),此时 Django 收到的是纯 HTTP 请求 —— 它不知道外面是 HTTPS,于是直接跳过写入 sessionid Cookie。
- 必须在 Nginx 配置中显式传递协议信息:
proxy_set_header X-Forwarded-Proto $scheme; - 并在 Django
settings.py中启用信任:SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - 漏掉任一环,
SESSION_COOKIE_SECURE=True就会静默失效,浏览器收不到 Cookie
SESSION_COOKIE_SAMESITE 设为 None 时的硬性要求
如果业务需要跨子域共享登录态(比如 app.example.com 和 api.example.com),你可能会设 SESSION_COOKIE_SAMESITE='None'。但 Chrome 80+、Firefox 79+、Safari 13.1+ 会强制拦截这种 Cookie,除非同时满足:
-
SESSION_COOKIE_SECURE=True(必须) - Nginx 确实终止了 HTTPS(不能只配
proxy_pass http://…) -
SESSION_COOKIE_DOMAIN='.example.com'(注意开头的点,表示包含所有子域) - 前端请求头中
credentials: 'include'已启用(Fetch API)或withCredentials=true(XMLHttpRequest)
任意一项缺失,浏览器控制台会报 Cookie “sessionid” has been rejected because it is in a cross-site context and its “SameSite” value is “None”。
立即学习“Python免费学习笔记(深入)”;
使用 Playwright 为 jimeng.jianying.com 管理浏览器会话,导入 cookies/localStorage 以自动化视频生成工作流,支持图片上传等功能
ALLOWED_HOSTS 和 SESSION_COOKIE_DOMAIN 不匹配的连锁反应
常见误配:ALLOWED_HOSTS = ['example.com'],但 SESSION_COOKIE_DOMAIN = '.example.com'。这会导致:
- Django 接收请求时检查 Host 头,只认
example.com,拒绝www.example.com或api.example.com - 即使 Cookie 写进去了,后续请求因 Host 不在白名单而被 400 拦截,根本到不了 Session 中间件
- 更隐蔽的问题:Django 日志里可能只记
Bad Request (400),不提示具体原因
建议统一用带点的通配:ALLOWED_HOSTS = ['.example.com'],并确保 DNS 解析和 Nginx server_name 也覆盖全部子域。
Nginx 缓存或代理头污染导致 Cookie 丢失
有些 Nginx 配置会无意中覆盖或清空关键响应头:
-
proxy_hide_header Set-Cookie;—— 这行会让 Nginx 直接吞掉 Django 返回的Set-Cookie,Session 彻底不可见 -
proxy_buffering on;+ 大响应体 —— 可能延迟甚至截断含Set-Cookie的响应头 - 未配置
proxy_cookie_path / "/";或proxy_cookie_domain off;—— 当 Nginx 做路径重写(如把/api/代理到后端根路径),Cookie 的Path可能被错写成/api/,导致后续请求不携带
最简验证法:curl -I https://yourdomain.com/login,看响应头是否含 Set-Cookie: sessionid=...。没有?问题一定出在 Nginx 层。
真正容易被忽略的点是:Django 的 Session 依赖链比表面看起来长得多 —— 从 Nginx 的 SSL 终结、Header 透传、Host 白名单,到 Cookie 的 Domain/SameSite/Secure 三属性协同生效,缺一不可。任何一个环节松动,表现都是“没登录”“反复跳登录页”,但错误日志里往往空空如也。

















