perf: Cache-Control headers so browsers and edge caches absorb traffic

Bandwidth diagnosis: iperf shows the proxy<->API VPN link at 65-78
Mbit/s and a fast client pulls 15.7 MB/s from a CDN but only ~66 KB/s
from the site — the Caddy host's public uplink is the scarce resource.
Max-ages mirror the server cache TTLs (latest 30s, HII 60s, forecast
120s, history/stats/stations 300s, static 1h, dashboard HTML 120s), so
repeat views come from browser cache and an edge proxy (e.g. Cloudflare
free tier in front of Caddy) can serve most traffic without touching
the uplink.
This commit is contained in:
2026-08-12 11:51:43 +07:00
parent d9c65bcf0c
commit 0b14e394ad
+29
View File
@@ -348,6 +348,35 @@ def _send_umami_event(path: str, method: str, status: int, host: str, user_agent
pass # analytics must never affect API behavior pass # analytics must never affect API behavior
# Cache-Control by path: lets browsers and any edge cache (e.g. Cloudflare in
# front of Caddy) absorb repeat traffic — the public uplink is the scarce
# resource. Max-ages mirror the server-side cache TTLs / data cadence.
_CACHE_CONTROL_RULES = (
("/static/", "public, max-age=3600"),
("/measurements/latest", "public, max-age=30"),
("/api/hii/", "public, max-age=60"),
("/measurements/history", "public, max-age=300"),
("/forecast", "public, max-age=120"),
("/api/stats", "public, max-age=300"),
("/stations", "public, max-age=300"),
)
@app.middleware("http")
async def cache_control_headers(request, call_next):
response = await call_next(request)
if request.method == "GET" and response.status_code == 200:
path = request.url.path
if path == "/":
response.headers.setdefault("Cache-Control", "public, max-age=120")
else:
for prefix, value in _CACHE_CONTROL_RULES:
if path.startswith(prefix):
response.headers.setdefault("Cache-Control", value)
break
return response
@app.middleware("http") @app.middleware("http")
async def umami_api_tracking(request, call_next): async def umami_api_tracking(request, call_next):
response = await call_next(request) response = await call_next(request)