diff --git a/src/app/api/basemap-tile/[...path]/route.ts b/src/app/api/basemap-tile/[...path]/route.ts index 6009a13..bd5db19 100644 --- a/src/app/api/basemap-tile/[...path]/route.ts +++ b/src/app/api/basemap-tile/[...path]/route.ts @@ -70,12 +70,17 @@ export async function GET( return NextResponse.json({ error: "upstream_too_large" }, { status: 413 }); } + // Buffer the body and re-emit. We deliberately drop upstream + // Content-Encoding + Content-Length: Node's fetch auto-decodes + // gzip/br responses, so forwarding the original encoding header makes + // the browser try to gunzip already-decoded bytes (or, worse, makes + // Next.js stream a Content-Length that doesn't match the decoded + // payload → HTTP/2 INTERNAL_ERROR mid-stream). + const body = await upstream.arrayBuffer(); + const headers = new Headers(); const ct = upstream.headers.get("content-type"); if (ct) headers.set("Content-Type", ct); - const ce = upstream.headers.get("content-encoding"); - if (ce) headers.set("Content-Encoding", ce); - if (contentLength) headers.set("Content-Length", contentLength); // Tiles + sprites + glyphs are immutable per path (versioned). Cache // aggressively to keep architots out of the per-tile critical path. @@ -84,5 +89,5 @@ export async function GET( "public, max-age=86400, stale-while-revalidate=604800, immutable", ); - return new NextResponse(upstream.body, { status: 200, headers }); + return new NextResponse(body, { status: 200, headers }); }