根本原因是django生产环境(debug=false)不提供静态文件服务,必须由nginx/whitenoise接管;static_root须正确定义并执行collectstatic,nginx需用alias正确映射至该目录,否则必404。

生产环境静态资源加载失败,根本原因只有一个:Django 本身不提供静态文件服务,而你没让 Web 服务器(Nginx/Apache)或中间件(WhiteNoise)接管这件事。
STATIC_ROOT 必须定义且 collectstatic 必须执行
开发时 STATICFILES_DIRS 让 runserver 能“找得到”你的 css/ 和 js/;但生产环境(DEBUG=False)下,Django 直接忽略 STATICFILES_DIRS 和所有应用内的 static/ 文件夹。
它只认一个地方:STATIC_ROOT 指向的目录。这个目录不是你手写的源码位置,而是 collectstatic 命令运行后生成的“统一交付包”。
-
STATIC_ROOT必须是绝对路径,例如BASE_DIR / "staticfiles"(不要和开发用的static/同名同位置) - 部署前必须手动执行
python manage.py collectstatic --noinput,否则staticfiles/是空的 - 若
STATIC_ROOT未定义,collectstatic会报错;若已定义但没运行命令,Nginx 就只能返回 404
Nginx 配置中 alias 和 root 容易写反
用 Nginx 服务静态文件时,location /static/ 块里必须用 alias,不是 root —— 这是 90% 的配置错误源头。
假设你 collectstatic 输出到 /app/staticfiles/,那么:
- ✅ 正确:
location /static/ { alias /app/staticfiles/; }(请求/static/css/main.css→ 映射到/app/staticfiles/css/main.css) - ❌ 错误:
location /static/ { root /app/staticfiles; }(请求/static/css/main.css→ 实际去找/app/staticfiles/static/css/main.css,多了一层/static) - 注意末尾斜杠:
alias值末尾必须带/,root值末尾不带
Vercel/Serverless 环境不能依赖文件系统路径
在 Vercel、AWS Lambda 等只读、无持久文件系统的平台,open(os.path.join(settings.BASE_DIR, 'static', ...)) 必然抛 FileNotFoundError —— 因为构建后原始 static/ 目录结构已不存在,只有 staticfiles/ 产物被打包进部署包。
- 必须用
whitenoise中间件,而不是自己拼路径读文件 -
STATICFILES_STORAGE设为whitenoise.storage.CompressedManifestStaticFilesStorage,确保 URL 哈希稳定、支持压缩 -
MIDDLEWARE中WhiteNoiseMiddleware必须紧接在SecurityMiddleware之后,顺序错会导致缓存头失效或 MIME 错误
浏览器报 MIME type ‘text/html’ 其实是 404 的伪装
当你看到 Refused to apply style from ‘/static/css/main.css’ because its MIME type (‘text/html’) is not a supported stylesheet MIME type,别急着查 CSS 语法 —— 这说明服务器根本没返回 CSS,而是返回了某个 HTML 页面(通常是 404 或登录页)。
- 打开 DevTools → Network → 点开那个
.css请求,看 Response 内容是不是一段 HTML(比如包含<h1>Not Found</h1>) - 这 100% 是路径映射失败:Nginx 没配对,或 WhiteNoise 没启用,或
collectstatic没跑,或文件压根没被收集进去(检查INSTALLED_APPS是否漏了django.contrib.staticfiles) - 特别注意:Vercel 上若用
STATIC_URL = 'static/'(无前导/),WhiteNoise 会无法匹配路由,必须写成'/static/'
最常被跳过的动作是:没验证 collectstatic 输出内容是否真包含你要的文件,以及没确认部署包里是否存在 staticfiles/ 目录及其内部结构。路径对了,服务方式对了,剩下只是同步问题。











