2025-03-05

다중 개발 서버 환경에서의 API 오리진 동적 설정: Next.js 미들웨어와 쿠키 활용

배경

회사의 메인 서비스는 약 10개의 개발 서버(dev1, dev2, …, dev10)를 운영 중이며, 각 서버는 인증 정보를 제외한 데이터가 독립적으로 동작한다.
내가 담당하고 있는 서비스는 메인 서비스가 아니여서 메인에서 레포지토리를 분리했지만, 메인 서비스와의 의존성이 남아있는 기능들이 꽤 있었고, 유입된 dev 서버에 따라 API origin을 동적으로 변경해야했다.
(e.g dev3으로 접속한 경우 dev3.api.com를 호출해야함)


그리고 하나 더 케이스가 있는데, 유입 경로와 별개로 수동으로도 dev 환경을 설정할 수 있도록 개발 서버에서 기능을 제공하고 있다.



정리하면 dev 서버를 설정하는 케이스 2가지가 있다. 하나는 유입링크 기반, 하나는 수동 변경.

referrer 사용하기

유입 경로는 요청이 어떤 사이트로부터 유입되었는지 알 수 있는 HTTP 헤더의 referrer값을 활용하기로 했다.
이 값은 서버에서도 http request의 header에서 접근할 수 있고, 클라이언트에서도 document.referrer를 통해 접근할 수 있다. (header의 referrer값을 브라우저가 설정함)
(참고: request header에서는 오타가 있다.(referer) 이유는 단순 실수라고 한다 링크)



처음에는 referrer값을 가져와 전역 상태관리에 저장 후 그 값을 참조하고 있었지만, 페이지가 서버 레벨에서 라우팅이 되는 경우에 referrer가 이전 페이지로 변경되어서 직접 참조하기 어려운 문제가 있다.

Cookie

referrer가 변경되는 문제가 있기 때문에 계속 참조할 수가 없었다. 그래서 최초 1회만 참조 후 쿠키에 저장하기로 했다.
쿠키를 참조하는 시점은 서버, 클라이언트 2개 케이스인데, 특히 서버의 경우 서버 컴포넌트에서 API를 조회하는 로직이 있을 경우, 서버 컴포넌트가 실행되기 전에 쿠키가 저장되어 있어야한다.

Middleware

Next.js의 middleware는 요청이 완료되기전 중간에 코드를 실행할 수 있고 redirect나 response까지 제어할 수 있는 기능이다.
referrer를 가져와 subdomain을 추출하고 쿠키를 저장하는 작업은 큰 부하가 걸리지 않은 작업이여서 middleware가 안성맞춤이라고 생각했다. (Next.js Middleware)

import { NextResponse, type NextRequest } from 'next/server'; import { COOKIE_KEY } from '@/constants'; export function middleware(request: NextRequest) { const headers = new Headers(request.headers); const isDev = process.env.NEXT_PUBLIC_SERVER_TYPE.includes('dev'); const referrer = request.headers.get('referer'); // 개발서버 도메인만 허용 + subdomain 추출 const matchedSubDomain = referrer?.match(/https:\/\/(dev[a-zA-Z0-9]*)\.service\.com/); // dev에서만 실행 if (isDev && matchedSubDomain?.[1]) { // Path를 루트로 설정하지 않으면 pathname별로 cookie가 생성되니 주의! headers.set('Set-Cookie', `${COOKIE_KEY}=${matchedDevDomain[1]}; Path=/`); } return NextResponse.next({ headers }); } export const config = { matcher: [ // match all routes except static files and APIs '/((?!api|_next/static|_next/image|favicon.ico).*)', ], };
middleware.js


시점별로 실행 순서를 정리해봤다.

Server

  1. dev3.service.com 페이지에서 my.service.com 페이지로 요청
  2. my.service.com의 middleware에서 referrer값 참조해 subdoamin추출 후(e.g dev3) 쿠키에 저장
  3. my.service.com의 page.tsx 에서 next/headers의 cookies를 통해 2번에서 저장한 쿠키를 가져와 API 요청 (Cookies)

Client

  1. Server의 1,2번과 동일
  2. 클라이언트에서 cookie에 저장된 subdomain를 가져옴 or 전역상태관리를 통해 subdomain을 가져옴

결론

개발 환경에 맞춰 수정을 했지만, 개발 전용 코드의 로직이 많아지니 코드의 복잡성도 올라가고 좀 번잡해지는 느낌이 든다.
많은 개발서버가 문제인지, 혹시 문제 해결의 접근을 잘못하고 있진 않은지 개발하면서도 고민을 많이했던 작업이였다.



다수의 개발서버를 효울적으로 관리할 수 있는 방법은 무엇일까?