Fix service worker serving the homepage when clicking a job/applicant card
CI/CD / CI · dotnet build (push) Successful in 38s
CI/CD / Deploy · hamkadr (push) Successful in 1m55s

Navigations now always hit the network (fresh, never stale/archived) and fall back only to an offline notice, never the cached homepage. HTML is no longer cached so 410s cannot poison the cache; static assets stay cache-first. CACHE bumped to v2 to force-replace the broken worker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-26 20:03:37 +03:30
parent 923a3fb90e
commit f0e0b82375
+17 -4
View File
@@ -336,14 +336,27 @@ app.MapPost("/like", async (HttpContext ctx, AppDbContext db, [FromForm] string
}).RequireAuthorization().DisableAntiforgery(); }).RequireAuthorization().DisableAntiforgery();
app.MapGet("/sw.js", () => Results.Content(""" app.MapGet("/sw.js", () => Results.Content("""
const CACHE = 'hamkadr-v1'; const CACHE = 'hamkadr-v2';
self.addEventListener('install', e => { self.skipWaiting(); e.waitUntil(caches.open(CACHE).then(c => c.addAll(['/']))); }); const OFFLINE = '<!doctype html><html lang="fa" dir="rtl"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>آفلاین</title><body style="font-family:Vazirmatn,system-ui,sans-serif;text-align:center;padding:48px 20px;color:#334155"><h2 style="margin:0 0 8px">اتصال اینترنت برقرار نیست</h2><p style="color:#64748b">صفحه باز نشد؛ اتصال خود را بررسی و دوباره تلاش کنید.</p><button onclick="location.reload()" style="margin-top:14px;padding:10px 24px;border:0;border-radius:10px;background:#0d9488;color:#fff;font:inherit;cursor:pointer">تلاش دوباره</button></body></html>';
self.addEventListener('install', e => { self.skipWaiting(); e.waitUntil(caches.open(CACHE).then(c => c.add('/'))); });
self.addEventListener('activate', e => { e.waitUntil(caches.keys().then(ks => Promise.all(ks.filter(k => k !== CACHE).map(k => caches.delete(k))))); self.clients.claim(); }); self.addEventListener('activate', e => { e.waitUntil(caches.keys().then(ks => Promise.all(ks.filter(k => k !== CACHE).map(k => caches.delete(k))))); self.clients.claim(); });
self.addEventListener('fetch', e => { self.addEventListener('fetch', e => {
const req = e.request; const req = e.request;
if (req.method !== 'GET' || new URL(req.url).origin !== location.origin) return; if (req.method !== 'GET' || new URL(req.url).origin !== location.origin) return;
e.respondWith(fetch(req).then(res => { const copy = res.clone(); caches.open(CACHE).then(c => c.put(req, copy)); return res; }) // Page navigations ALWAYS go to the network so listings are fresh (never a stale/archived card).
.catch(() => caches.match(req).then(m => m || caches.match('/')))); // We only fall back when the device is truly offline — to a cached copy of THAT exact page, or an
// offline notice. We never substitute the homepage for a detail page (that was the "clicking a job
// just shows the homepage" bug) and we never cache HTML, so a 410 can't poison the cache.
if (req.mode === 'navigate') {
e.respondWith(fetch(req).catch(() => caches.match(req).then(m =>
m || new Response(OFFLINE, { headers: { 'Content-Type': 'text/html; charset=utf-8' } }))));
return;
}
// Static assets (css/js/fonts/images) are fingerprinted — cache-first is safe and fast.
e.respondWith(caches.match(req).then(hit => hit || fetch(req).then(res => {
if (res.ok && res.type === 'basic') { const copy = res.clone(); caches.open(CACHE).then(c => c.put(req, copy)); }
return res;
})));
}); });
self.addEventListener('push', e => { self.addEventListener('push', e => {
let d = { title: 'همکادر', body: 'فرصت جدید برای شما', url: '/' }; let d = { title: 'همکادر', body: 'فرصت جدید برای شما', url: '/' };