logo

미들웨어 활용하기

미들웨어의 사용방안을 조금 더 깊게 살펴보기

41 조회

0 추천

2,052 단어

11분 예상

2025. 02. 18. 게시

2025. 02. 18. 수정

luasenvy 작성

CC BY-NC-SA 4.0

인터페이스 정규화

웹 서버는 일반적으로 모든 요청이 반드시 한 번은 통과하는 공통된 구간이 있다. 이곳에 기능을 삽입하여 전체적인 요청을 제어하는 프로그램을 우리는 미들웨어라고 부른다. 이 미들웨어는 성능은 물론이고 개발방식에 이르기 까지 전반적인 웹 서버 전체에 영향을 주기 때문에 웹 서버의 성격 자체를 규정하는 중요한 프로그램이 된다.

Request와 Response를 정규화한다는 것은 곳 클라이언트와 서버의 통신과 리스너와 어플리케이션의 통신을 정의한다고 풀이할 수도 있다. 이것은 단순히 URL 라우트를 정의하는 것과는 다르게 상세한 부분까지 다룰 수 있는데 데이터 구조를 포함하여 통신 프로토콜이나 오류처리등 다방면으로 활용할 수 있기 때문에 높은 편의성을 가지며 그만큼 가장 중요한 프로그램이 된다. 사실상 웹 서버가 미들웨어라고 봐도 과언이 아니다.

미들웨어 구성 중점

미들웨어 구성할 때에는 다양한 중점들이 있지만 역시 가장 중요한 것은 오류 없이, 빠르게, 정확하고 통일된 요청을 어플리케이션으로 전달하는 것이다. 미들웨어라는 이름 그대로 중간자의 역할을 충실히 수행하는 것이다.

무중단

모든 프로그램이 동일하지만 무중단 서비스를 구성할 수 있도록 하는 것이 가장 중요하다. 예기치 못한 오류는 500으로 응답할 수 있도록 오류처리기를 등록해야 할 것이다. 당연히 500 에러자체도 정상이 아니기 때문에 어플리케이션의 오류를 제외하고 미들웨어에서 오류가 나는 일이 없도록 신중해야 한다.

성능

가장 간단하고 빠른 처리를 할 수 있도록 고려해야한다. 미들웨어의 작업은 곧 웹 서버 전체의 응답시간을 상승시키기 때문에 되도록 복잡한 작업은 어플리케이션 레이어에서 할 수 있도록 해야한다. 부득이하게 미들웨어에서 큰 작업을 해야하는 경우가 생겼다면 전체 아키텍처를 변경할 수 없는지 고려할 떄가 됐다는 것이다. 처음부터 단추를 잘 못 끼웠을 가능성이 아주 높다.

생산성

클라이언트와 서버의 통신스펙을 규약하여 개발을 어떤식으로 유도할지 규칙을 정할 수 있다. 이것은 어플리케이션 레이어도 동일하게 적용되기 때문에 만약 프론트엔드와 백엔드로 나누어 작업하는 경우라면 양측 모두 고려하는 것이 좋다. 예를 들면 개발 생산성과 관련된 규칙을 다음 처럼 정리해볼 수 있다.

  • 모든 데이터는 application/json으로 통신한다.
  • 어플리케이션 레이어에서 BODY데이터는 두번째 파라미터를 통해 얻을 수 있다.
  • 파일은 multipart로 통신하며 어플리케이션 레이어에서 세번째 파라미터를 통해 얻을 수 있다.

nextjs처럼 많이 쓰이는 프레임워크로 개발을 한다면 각 개인이 숙지하고 있다는 가정이 필요하지만 동일한 규칙을 따르게 하여 부가적인 학습비용과 성능하락을 제거할 수도 있다. 직접 만든다고 해서 틀린 것은 아니지만 결국 개개인의 기술 숙련도와 관계없이 생산성을 유지할 수 있도록 함이 목적임을 잊지 말아야 한다.

또한, 미들웨어의 중대한 변경이 있다면 모든 프로그램에 영향이 가게되기 때문에 관련된 모든 소스를 수정해야하는 경우도 생길 수 있으므로 마찬가지로 처음 구성할 때부터 신중을 기하여 구성하는 것이 바람직하다.

활용

세션처리

위 세가지가 중점적으로 고려해야할 사항이라면 선택적으로 고려해볼만한 사항들도 존재한다. 가장 대표적인것은 세션처리이다. 사용자의 로그인 상태를 확인하여 허가되지 않은 접근에 대해서는 모든 요청을 거부하는 방식을 적용할 수 있다. nextjs의 경우 next-auth 패키지를 사용하면 쉽게 추가할 수 있다.

로그

또는, 개발모드로 실행시 모든 요청의 상세내역을 로그를 남겨 개발에 편의를 제공하는 것도 하나의 미들웨어 활용법이다. 이 경우에는 운영환경에서 작동시에는 성능에 영향을 주지 않고 민감한 정보가 로그로 남지 않도록 처리해야하며 로그가 디스크 용량을 가득 채우게 되면 서버가 중단되기 때문에 적절한 시점을 고려하여 사용자가 이해하기 쉬운 포맷을 설정해야 한다.

정규식

nextjs에서 제공하는 URL 매치 정규식은 pillarjs/path-to-regexp를 사용하고 있다. 일반적으로 우리가 생각하고 있는 regex와는 규칙이 조금 다른 부분들이 있기 때문에 상세설정을 위해서는 한 번은 확인해야한다. 정규식을 통하여 URL이 매치되지 않으면 통과시키는등의 작업을 진행하여 위의 세션처리와 엮어 사용할 수 있다.1

POST 미들웨어

어플리케이션으 실행되는 시점을 기준으로 그 전을 Pre, 그 후를 Post로 구분하여 지칭하기도 한다. 흔히 미들웨어라고 하면 Pre 미들웨어를 말하는 것으로 생각하면 된다. 각각 어플리케이션 기능이 수행된 전,후 시점으로 구분되기 때문에 Pre는 요청을 정규화하고 Post는 응답을 정규화하는 목적으로 사용된다.

이 두가지 성격의 미들웨어를 명시적으로 구분하는 경우도 있지만 nextjs에서는 구분 없이 미들웨어 핸들러 하나만을 사용한다. Pre 방식으로 작동하기 때문에 제공되는 인자도 NextRequest 하나이며 요청에 대한 정규화 기능을 제공할 수 있다.

import { NextResponse } from "next/server";

const PostMiddleware = (res: NextResponse) => {
  // 버전정보 삽입
  res.headers.set("X-My-Version", "1.0.0");

  // 개발용 응답 로그
  console.debug(`${resStamp(res)}\n`);

  return res;
};

export default function (req: NextRequest) {
  return PostMiddleware(NextResponse.next());
}

미들웨어의 전처리를 완료하면 제공되는 내장함수인 NextResponse.next를 호출하여 다음 수행될요청된 라우트와 매치되는 어플리케이션으로 요청을 넘겨줄 수 있다. 이 함수는 Response 객체를 반환하며, 미들웨어가 이 Response 객체를 다시 반환시켜 서버가 클라이언트로 보낼 응답을 정의할 수 있다.

이 응답객체는 생각보다 핸들링하기 까다롭기 때문에 응답을 정규화 할 생각이 있다면 어플리케이션과 미들웨어의 작동방식을 잘 강구하여 조화롭게 구성해야 한다.2

Footnotes

  1. 권한이 불필요한 페이지를 선정하거나 또는 로그인 페이지는 권한이 없는 사용자만 접근할 수 있는 등

  2. 까다롭다는 말은 다시 말해 성능과 유지보수에 영향을 줄 수도 있다는 말이 된다. 응답 헤더 추가와 같은 간단한 작업이 아니라면 잘 고려해서 선택해야 할 것이다.