100 lines
3.2 KiB
TypeScript
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 },
|
|
);
|
|
}
|
|
}
|