maximize Cloudflare edge caching

This commit is contained in:
2569718930@qq.com
2026-06-10 19:11:58 +08:00
parent 081bf9cc05
commit 1494db8e09
18 changed files with 421 additions and 42 deletions
+16 -2
View File
@@ -9,6 +9,7 @@ import {
finishProxyTimedResponse,
type ProxyTimer,
} from "@/lib/proxy-timing";
import { NO_STORE_CACHE_CONTROL } from "@/lib/proxy-cache-policy";
const PASSTHROUGH_UPSTREAM_STATUSES = new Set([
400,
@@ -85,6 +86,10 @@ export function buildUpstreamErrorResponse(
}
return NextResponse.json(body, {
headers: {
"Cache-Control": NO_STORE_CACHE_CONTROL,
"Cloudflare-CDN-Cache-Control": NO_STORE_CACHE_CONTROL,
},
status: clientStatusFromUpstream(upstreamStatus),
});
}
@@ -106,7 +111,13 @@ export function buildProxyExceptionResponse(
body.detail = String(error);
}
return NextResponse.json(body, { status: options.status ?? 500 });
return NextResponse.json(body, {
headers: {
"Cache-Control": NO_STORE_CACHE_CONTROL,
"Cloudflare-CDN-Cache-Control": NO_STORE_CACHE_CONTROL,
},
status: options.status ?? 500,
});
}
export async function proxyBackendJsonGet(
@@ -185,7 +196,10 @@ export async function proxyBackendJsonGet(
? buildCachedJsonResponse(req, data, responseCacheControl)
: NextResponse.json(data, {
headers: responseCacheControl
? { "Cache-Control": responseCacheControl }
? {
"Cache-Control": responseCacheControl,
"Cloudflare-CDN-Cache-Control": responseCacheControl,
}
: undefined,
});
const withCookies = applyAuthResponseCookies(response, auth.response);
+1
View File
@@ -28,6 +28,7 @@ export function buildCachedJsonResponse(
const etag = buildEtag(body);
const headers = new Headers({
"Cache-Control": cacheControl,
"Cloudflare-CDN-Cache-Control": cacheControl,
ETag: etag,
"Content-Type": "application/json; charset=utf-8",
});
+51 -11
View File
@@ -4,7 +4,32 @@ export type ProxyCachePolicy = {
revalidateSeconds?: number;
};
const NO_STORE_CACHE_CONTROL = "no-store, max-age=0";
export const NO_STORE_CACHE_CONTROL = "no-store, max-age=0";
export const CLOUDFLARE_EDGE_TTL_SEC = {
cityDetail: 60,
cityDetailStale: 300,
cityList: 300,
cityListStale: 3600,
landingPage: 600,
scanTerminal: 300,
scanTerminalStale: 900,
staticAsset: 31536000,
systemStatus: 60,
} as const;
export function buildPublicEdgeCacheControl(
sMaxageSeconds: number,
staleWhileRevalidateSeconds = Math.max(sMaxageSeconds * 3, 30),
browserMaxAgeSeconds = 0,
) {
return [
"public",
`max-age=${Math.max(0, Math.floor(browserMaxAgeSeconds))}`,
`s-maxage=${Math.max(1, Math.floor(sMaxageSeconds))}`,
`stale-while-revalidate=${Math.max(0, Math.floor(staleWhileRevalidateSeconds))}`,
].join(", ");
}
export function isForceRefreshValue(value: string | null | undefined) {
return String(value || "").trim().toLowerCase() === "true";
@@ -12,7 +37,7 @@ export function isForceRefreshValue(value: string | null | undefined) {
export function buildForceRefreshProxyCachePolicy(
forceRefresh: string | null | undefined,
revalidateSeconds = 15,
revalidateSeconds: number = CLOUDFLARE_EDGE_TTL_SEC.scanTerminal,
): ProxyCachePolicy {
if (isForceRefreshValue(forceRefresh)) {
return {
@@ -22,17 +47,17 @@ export function buildForceRefreshProxyCachePolicy(
}
return {
fetchMode: "revalidate",
responseCacheControl: `public, max-age=0, s-maxage=${revalidateSeconds}, stale-while-revalidate=${Math.max(
revalidateSeconds * 3,
30,
)}`,
responseCacheControl: buildPublicEdgeCacheControl(
revalidateSeconds,
Math.max(revalidateSeconds * 3, CLOUDFLARE_EDGE_TTL_SEC.scanTerminalStale),
),
revalidateSeconds,
};
}
export function buildCityDetailProxyCachePolicy(
forceRefresh: string | null | undefined,
revalidateSeconds = 15,
revalidateSeconds: number = CLOUDFLARE_EDGE_TTL_SEC.cityDetail,
): ProxyCachePolicy {
if (isForceRefreshValue(forceRefresh)) {
return {
@@ -42,14 +67,29 @@ export function buildCityDetailProxyCachePolicy(
}
return {
fetchMode: "revalidate",
responseCacheControl: `public, max-age=${revalidateSeconds}, s-maxage=${revalidateSeconds}, stale-while-revalidate=${Math.max(
revalidateSeconds * 3,
30,
)}`,
responseCacheControl: buildPublicEdgeCacheControl(
revalidateSeconds,
Math.max(revalidateSeconds * 3, CLOUDFLARE_EDGE_TTL_SEC.cityDetailStale),
Math.min(revalidateSeconds, 30),
),
revalidateSeconds,
};
}
export function buildCityListCacheControl() {
return buildPublicEdgeCacheControl(
CLOUDFLARE_EDGE_TTL_SEC.cityList,
CLOUDFLARE_EDGE_TTL_SEC.cityListStale,
);
}
export function buildStaticCityListFallbackCacheControl() {
return buildPublicEdgeCacheControl(
CLOUDFLARE_EDGE_TTL_SEC.cityList,
CLOUDFLARE_EDGE_TTL_SEC.cityListStale,
);
}
export function buildScanTerminalResponseCacheControl(
data: unknown,
readyCacheControl: string,