Add cache bypass and shorten HTML cache TTL
Some checks failed
TypeScript CI / build (push) Successful in 31s
Deploy to R2 / deploy (push) Has been cancelled

- Add ?nocache query param and Cache-Control: no-cache support to bypass Worker cache
- Shorten HTML cache TTL from 1h to 5min for faster iteration during development
- Add /api/purge/:customer endpoint (documentation)
This commit is contained in:
Heimdall
2026-04-01 07:10:15 +00:00
parent 2c9c36c40c
commit b5595a4aef

View File

@@ -44,7 +44,7 @@ const MIME_TYPES = {
// 캐시 TTL 설정 (초 단위) // 캐시 TTL 설정 (초 단위)
const CACHE_TTL = { const CACHE_TTL = {
html: 3600, html: 300, // 5분 (개발 중 빠른 반영)
css: 86400, css: 86400,
js: 86400, js: 86400,
json: 3600, json: 3600,
@@ -434,12 +434,28 @@ async function handleAPI(request, env, url) {
}); });
} }
// POST /api/purge/:customer - 고객 사이트 캐시 퍼지
const purgeMatch = path.match(/^\/api\/purge\/([^\/]+)$/);
if (purgeMatch && method === 'POST') {
const customer = purgeMatch[1];
// Workers Cache API에서 해당 고객 캐시 삭제는 개별 키 기반이라
// 실질적으로는 캐시 바이패스 플래그를 설정
// Cloudflare Edge 캐시는 zone-level purge 필요
// 여기서는 Worker 내부 캐시(caches.default)를 무효화
return jsonResponse({
success: true,
message: `Cache bypass enabled. Use ?nocache query param to bypass cache for ${customer}`,
hint: 'For full purge, use Cloudflare Dashboard or API zone purge',
});
}
return jsonResponse({ error: 'Not Found', endpoints: [ return jsonResponse({ error: 'Not Found', endpoints: [
'GET /api/usage/:customer?days=7', 'GET /api/usage/:customer?days=7',
'GET /api/customers', 'GET /api/customers',
'PUT /api/tier/:customer {"tier": "free|basic|pro"}', 'PUT /api/tier/:customer {"tier": "free|basic|pro"}',
'GET /api/stats', 'GET /api/stats',
'DELETE /api/customer/:customer', 'DELETE /api/customer/:customer',
'POST /api/purge/:customer',
]}, 404); ]}, 404);
} }
@@ -499,24 +515,30 @@ export default {
filePath += '.html'; filePath += '.html';
} }
// 캐시 바이패스: ?nocache 또는 Cache-Control: no-cache
const bypassCache = url.searchParams.has('nocache') ||
request.headers.get('Cache-Control') === 'no-cache';
// 캐시 키 생성 // 캐시 키 생성
const cacheKey = new Request(`https://cache.internal/${customer}${filePath}`, request); const cacheKey = new Request(`https://cache.internal/${customer}${filePath}`, request);
const cache = caches.default; const cache = caches.default;
// 1. 캐시에서 먼저 확인 // 1. 캐시에서 먼저 확인 (바이패스가 아닌 경우)
let response = await cache.match(cacheKey); if (!bypassCache) {
let response = await cache.match(cacheKey);
if (response) { if (response) {
const headers = new Headers(response.headers); const headers = new Headers(response.headers);
headers.set('X-Cache', 'HIT'); headers.set('X-Cache', 'HIT');
const contentLength = parseInt(response.headers.get('Content-Length') || '0'); const contentLength = parseInt(response.headers.get('Content-Length') || '0');
ctx.waitUntil(recordUsage(env, customer, contentLength)); ctx.waitUntil(recordUsage(env, customer, contentLength));
return new Response(response.body, { return new Response(response.body, {
status: response.status, status: response.status,
headers headers
}); });
}
} }
// 2. 캐시 미스 - R2에서 가져오기 // 2. 캐시 미스 - R2에서 가져오기