Files
2026-09-15 10:00:42 +09:00

100 lines
3.2 KiB
TypeScript

import type { NextRequest } from "next/server";
const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id";
const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
const GIS_UPLOAD_PATH = "/sewerage-service/api/v1/map/gisUploads";
const HOP_BY_HOP_HEADERS = [
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
];
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const maxDuration = 600;
/**
* multipart 본문을 한 번 버퍼링해 백엔드에 정확한 Content-Length로 전달한다.
* 로컬 Node Web Stream의 chunked 재전송 지연을 피하며, 허용 크기는 백엔드의 50MB 제한을 따른다.
*/
export async function POST(request: NextRequest) {
const sewerageApiUrl = process.env.SEWERAGE_API_URL?.trim();
if (!sewerageApiUrl) {
return Response.json(
{
status: 503,
message: "GIS 업로드 서버 주소가 설정되지 않았습니다.",
code: "GIS_UPLOAD_PROXY_NOT_CONFIGURED",
},
{ status: 503 },
);
}
if (!request.body) {
return Response.json(
{
status: 400,
message: "GIS 업로드 요청 본문이 없습니다.",
code: "GIS_UPLOAD_BODY_REQUIRED",
},
{ status: 400 },
);
}
const requestHeaders = new Headers(request.headers);
HOP_BY_HOP_HEADERS.forEach((headerName) => requestHeaders.delete(headerName));
requestHeaders.delete("host");
// 원 요청 길이는 Next가 다시 구성한 multipart 본문 길이와 다를 수 있어 아래에서 다시 설정한다.
requestHeaders.delete("content-length");
// undici fetch는 curl 등이 대용량 요청에 붙이는 Expect: 100-continue 전달을 지원하지 않는다.
requestHeaders.delete("expect");
// middleware rewrite와 동일하게 로그인 쿠키의 인증 값을 백엔드 요청 헤더에 주입한다.
const token = request.cookies.get(CLAIM_NAME)?.value;
const userId = request.cookies.get(AUTH_USER_ID)?.value;
if (token) requestHeaders.set(CLAIM_NAME, token);
if (userId) requestHeaders.set(AUTH_USER_ID, userId);
const targetUrl = `${sewerageApiUrl.replace(/\/$/, "")}${GIS_UPLOAD_PATH}`;
try {
const requestBody = await request.arrayBuffer();
requestHeaders.set("content-length", String(requestBody.byteLength));
const upstreamResponse = await fetch(targetUrl, {
method: "POST",
headers: requestHeaders,
body: requestBody,
cache: "no-store",
signal: request.signal,
});
const responseHeaders = new Headers(upstreamResponse.headers);
HOP_BY_HOP_HEADERS.forEach((headerName) =>
responseHeaders.delete(headerName),
);
return new Response(upstreamResponse.body, {
status: upstreamResponse.status,
statusText: upstreamResponse.statusText,
headers: responseHeaders,
});
} catch (error) {
console.error("[GIS_UPLOAD_PROXY] 백엔드 업로드 요청 실패", error);
return Response.json(
{
status: 502,
message:
"GIS 업로드 서버 연결이 중단되었습니다. 잠시 후 다시 시도하세요.",
code: "GIS_UPLOAD_PROXY_FAILED",
},
{ status: 502 },
);
}
}