bigywater.tech
Flask · 176

静态文件生产部署

静态文件该由谁来发?缓存头怎么设?gzip 能省多少?长缓存之后怎么更新?这篇用真实的 gunicorn 与 nginx 把每一步的响应头与吞吐量出来。

3459 → 6607
同一个 CSS 的请求/秒:Flask static 路由与 nginx 直接发文件
8.3%
46 KB 的 CSS 经 nginx gzip 后的体积占比
?v=哈希
让长缓存的静态文件在内容变化后失效的 URL 写法

Flask 的缓存头

实测 · 本机执行输出
  [默认] Cache-Control: no-cache | ETag: True | Last-Modified: True | 带 If-None-Match 再请求 → 304
  [SEND_FILE_MAX_AGE_DEFAULT = 31536000] Cache-Control: public, max-age=31536000 | ETag: True | Last-Modified: True | 带 If-None-Match 再请求 → 304

上一篇:ProxyFix 的作用;下一篇:媒体文件生产部署。

吞吐

实测 · 本机执行输出
  Flask static 路由(gunicorn sync×4)3459 请求/秒 | nginx 直接发静态文件 6607 请求/秒 | (对照:经 nginx 代理到 Flask 的动态页 / 1321 请求/秒)

压测工具是 ApacheBench,与服务同机运行,每个数字只测一次,只看相对关系。

gzip 与 expires

实测 · 本机执行输出
  不带 Accept-Encoding:47139 字节,Content-Encoding=None,Cache-Control=max-age=31536000
  带 Accept-Encoding: gzip:3911 字节(8.3%),Content-Encoding=gzip,Vary=None

缓存失效

实测 · 本机执行输出
  内容改之前 URL: /static/app.css?v=3390b73b | 改之后 URL: /static/app.css?v=eaf53a50 → URL 变了,浏览器会当作新资源重新下载

分步演示

静态文件生产部署
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。nginx 1.31.6(自己的配置、非默认端口)、gunicorn sync、ApacheBench
    • 没有验证:浏览器里实际的缓存命中表现、gzip_static 预压缩、brotli、CDN 的缓存行为、WhiteNoise 这类由 Python 直接发静态文件的方案、HTTP/2 下多个小文件的表现
    京ICP备2026067502号-1京公网安备11010502063487号