Files
lotteryFront/proxy.ts
kang ce1aca8905
Some checks failed
lotteryfront CI / build (push) Has been cancelled
feat: 重构和优化多个组件,增强性能和可维护性
2026-06-30 11:42:05 +08:00

60 lines
1.6 KiB
TypeScript

import { NextResponse } from "next/server";
import { lotteryApiOrigin } from "./src/lib/lottery-api-base";
import { generateCSP, nonCspSecurityHeaders } from "./src/lib/csp-config";
type RuntimeOriginsEnvelope = {
code?: number;
data?: {
iframe_allowed_origins?: unknown;
};
};
const RUNTIME_ORIGINS_TTL_MS = 60_000;
let cachedRuntimeOrigins: string[] | null = null;
let cachedAt = 0;
async function loadRuntimeOrigins(): Promise<string[]> {
if (cachedRuntimeOrigins !== null && Date.now() - cachedAt < RUNTIME_ORIGINS_TTL_MS) {
return cachedRuntimeOrigins;
}
try {
const url = `${lotteryApiOrigin()}/api/v1/integration/runtime-origins`;
const response = await fetch(url, {
headers: { Accept: "application/json" },
cache: "no-store",
});
if (!response.ok) return [];
const payload = (await response.json()) as RuntimeOriginsEnvelope;
const origins = payload.data?.iframe_allowed_origins;
if (!Array.isArray(origins)) return [];
cachedRuntimeOrigins = origins.filter((origin): origin is string => typeof origin === "string");
cachedAt = Date.now();
return cachedRuntimeOrigins;
} catch {
return cachedRuntimeOrigins ?? [];
}
}
export async function proxy(): Promise<NextResponse> {
const response = NextResponse.next();
const runtimeOrigins = await loadRuntimeOrigins();
response.headers.set("Content-Security-Policy", generateCSP(runtimeOrigins));
for (const header of nonCspSecurityHeaders) {
response.headers.set(header.key, header.value);
}
return response;
}
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico|.*\\..*).*)"],
};