mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
fix: stop iOS Safari heuristic-caching stale UI pages
User reported 'still broken' on /ui/tags/ai/ right after the 20-card cap shipped — the deployed HTML was correct (verified in-pod: 20 cards + View all 363 posts) but Safari was serving a heuristically cached copy of the previous template. UI HTML responses had no Cache-Control at all. - core/middleware.NoCacheUiPagesMiddleware: /ui/* HTML → Cache-Control: no-cache, no-store, must-revalidate (+ Pragma/Expires). API untouched. - tag_detail: defensive width:100% + box-sizing on .tags-page/.apple-card
This commit is contained in:
@@ -3,6 +3,27 @@ from django.urls import resolve
|
|||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.middleware.locale import LocaleMiddleware
|
from django.middleware.locale import LocaleMiddleware
|
||||||
|
|
||||||
|
|
||||||
|
class NoCacheUiPagesMiddleware:
|
||||||
|
"""Never let browsers (esp. iOS Safari's heuristic cache) serve stale UI pages.
|
||||||
|
|
||||||
|
Deployments change templates frequently; without an explicit Cache-Control
|
||||||
|
Safari may cache the HTML heuristically and users keep seeing the previous
|
||||||
|
version even after a fix ships ("did you fix it? still broken"). UI pages
|
||||||
|
are cheap to render; always fetch fresh.
|
||||||
|
"""
|
||||||
|
def __init__(self, get_response):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
|
response = self.get_response(request)
|
||||||
|
if request.path.startswith('/ui/') and response.get('Content-Type', '').startswith('text/html'):
|
||||||
|
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||||||
|
response['Pragma'] = 'no-cache'
|
||||||
|
response['Expires'] = '0'
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class CustomLocaleMiddleware(LocaleMiddleware):
|
class CustomLocaleMiddleware(LocaleMiddleware):
|
||||||
def process_request(self, request):
|
def process_request(self, request):
|
||||||
url_path = request.path_info.lstrip('/')
|
url_path = request.path_info.lstrip('/')
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ LOCALE_INDEPENDENT_PATHS = [
|
|||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||||
|
'core.middleware.NoCacheUiPagesMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'core.middleware.CustomLocaleMiddleware', # 使用自定义中间件
|
'core.middleware.CustomLocaleMiddleware', # 使用自定义中间件
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
|||||||
@@ -13,12 +13,14 @@
|
|||||||
.tags-page {
|
.tags-page {
|
||||||
max-width: 1080px; margin: 0 auto; padding: 2rem 1.25rem 3rem;
|
max-width: 1080px; margin: 0 auto; padding: 2rem 1.25rem 3rem;
|
||||||
color: var(--apple-text);
|
color: var(--apple-text);
|
||||||
|
width: 100%; box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.apple-card {
|
.apple-card {
|
||||||
background: #fff; border-radius: var(--apple-radius-lg);
|
background: #fff; border-radius: var(--apple-radius-lg);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.05);
|
||||||
padding: 1.5rem; margin-bottom: 1.25rem;
|
padding: 1.5rem; margin-bottom: 1.25rem;
|
||||||
|
width: 100%; box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Tag header ── */
|
/* ── Tag header ── */
|
||||||
|
|||||||
Reference in New Issue
Block a user