TL;DR

  • Interceptor/Middleware 패턴의 핵심 개념을 빠르게 파악할 수 있다.
  • 배경과 이유를 통해 왜 필요한지 맥락을 이해할 수 있다.
  • 특징과 상세 내용을 통해 실무 적용 포인트를 확인할 수 있다.

1. 개념

Interceptor/Middleware 패턴의 핵심 정의와 문제 공간을 간단히 정리한다.

2. 배경

이 주제가 등장한 기술적·조직적 배경과 기존 접근의 한계를 설명한다.

3. 이유

왜 지금 이 방식을 채택해야 하는지, 기대 효과와 트레이드오프를 함께 정리한다.

4. 특징

핵심 동작 방식, 장단점, 적용 시 주의점을 빠르게 훑을 수 있도록 요약한다.

5. 상세 내용

Interceptor/Middleware 패턴

작성일: 2026-03-11 카테고리: Backend / Design Pattern / Architecture 포함 내용: Interceptor, Middleware, Filter, Chain of Responsibility, Pipes and Filters, POSA2, GoF, Express.js, Spring HandlerInterceptor, Servlet Filter, Koa Onion Model, AOP, Decorator, 횡단 관심사, Cross-Cutting Concerns, gRPC Interceptor, Service Mesh, Sidecar


1. 개요

┌─────────────────────────────────────────────────────────────────┐
│           Interceptor/Middleware 패턴이란?                       │
│                                                                   │
│  정의:                                                           │
│  A에서 B로 이동하는 요청/응답을 중간 경로에서 가로채어           │
│  횡단 관심사(Cross-Cutting Concerns)를 처리하는 아키텍처 패턴    │
│                                                                   │
│  비유: 공항 보안 검색대                                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  승객(요청) ──► 신분확인 ──► 짐검사 ──► 보안검색 ──► 탑승│    │
│  │                                                          │    │
│  │  각 검색대는:                                            │    │
│  │  ├── 독립적으로 동작 (관심사의 분리)                      │    │
│  │  ├── 순서가 중요 (신분확인 → 짐검사 순서)                │    │
│  │  ├── 통과/차단을 결정 (필터링)                            │    │
│  │  └── 승객은 검색대 내부 로직을 모름 (투명성)              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  핵심 가치:                                                      │
│  ├── 인증, 로깅, 압축, CORS 등을 비즈니스 로직에서 완전 분리    │
│  ├── 기존 코드 수정 없이 새로운 관심사 추가 (개방-폐쇄 원칙)    │
│  └── 프레임워크마다 이름만 다를 뿐 본질은 동일                   │
│                                                                   │
│  프레임워크별 이름:                                              │
│  ├── Java Servlet  → Filter                                      │
│  ├── Spring MVC    → HandlerInterceptor                          │
│  ├── Express.js    → Middleware                                   │
│  ├── Django        → Middleware                                   │
│  ├── Rails         → before_action (구 before_filter)            │
│  ├── ASP.NET MVC   → Action Filter                               │
│  ├── gRPC          → Interceptor                                 │
│  └── NestJS        → Middleware + Interceptor + Guard + Pipe     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2. 용어의 어원과 기원

2.1 “Intercept”의 라틴어 어원

┌─────────────────────────────────────────────────────────────────┐
│                 Intercept의 어원                                  │
│                                                                   │
│  라틴어 분해:                                                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  inter-   (사이에, between)                              │    │
│  │     +                                                    │    │
│  │  capere   (잡다, to seize)                               │    │
│  │     =                                                    │    │
│  │  intercipere  (통과 중에 가로채다)                       │    │
│  │                                                          │    │
│  │  Proto-Indo-European 어근: *kap- "붙잡다"                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  로마 군사 용어에서 유래:                                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  interceptores = 적의 전령을 매복 공격하여               │    │
│  │                  군사 문서를 탈취하는 기병대              │    │
│  │                                                          │    │
│  │  [아군 진영] ←─── interceptores ───X─── [적 전령]       │    │
│  │                   (매복 기병대)          (문서 탈취)      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  영어 명사 interceptor 최초 기록: 1590년대                       │
│  군사 항공 (1930년대~): 적기를 차단하는 고속 전투기              │
│                                                                   │
│  핵심 의미 (소프트웨어에서도 동일):                              │
│  "A에서 B로 이동 중인 무언가를 중간 경로에서 가로채는 행위"     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2.2 세 가지 핵심 용어의 관계

┌─────────────────────────────────────────────────────────────────┐
│          Middleware / Interceptor / Filter의 관계                 │
│                                                                   │
│  Middleware (미들웨어)                                            │
│  ├── 의미: 위치 개념 (가장 넓은 추상 계층)                       │
│  ├── 기원: 1968년 NATO Software Engineering Conference           │
│  │         Alex d'Agapeyeff가 최초 사용                          │
│  ├── 원래 뜻: OS와 응용 프로그램 사이에 위치하는 소프트웨어     │
│  └── 시대별 변화:                                                │
│      ├── 1968: OS-앱 사이의 계층                                 │
│      ├── 1990s: 분산시스템 인프라 (CORBA, MOM)                   │
│      └── 2010s: Express.js 요청 처리 함수 체인                   │
│                                                                   │
│  Interceptor (인터셉터)                                          │
│  ├── 의미: 행위 개념 (중간에 삽입되어 가로채는 동작)             │
│  ├── 기원: 1990년대 CORBA 분산시스템                             │
│  └── 공식 문서화: POSA2 (2000)                                   │
│                                                                   │
│  Filter (필터)                                                   │
│  ├── 의미: 처리 개념 (통과/걸러냄 판단)                          │
│  ├── 기원: Java Servlet 2.3 (2000-2001)                          │
│  └── 패턴 문서화: Core J2EE Patterns (2001)                      │
│      "Intercepting Filter" 패턴                                  │
│                                                                   │
│  관계:                                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  동의어가 아니지만, 완전히 분리된 것도 아님              │    │
│  │                                                          │    │
│  │  ┌─── Middleware (어디에?) ───────────────────┐         │    │
│  │  │  ┌─── Interceptor (무엇을?) ────────┐      │         │    │
│  │  │  │  ┌─── Filter (어떻게?) ────┐     │      │         │    │
│  │  │  │  │  통과/차단 결정         │     │      │         │    │
│  │  │  │  └─────────────────────────┘     │      │         │    │
│  │  │  │  가로채서 처리                   │      │         │    │
│  │  │  └──────────────────────────────────┘      │         │    │
│  │  │  중간 계층에 위치                          │         │    │
│  │  └────────────────────────────────────────────┘         │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Chain of Responsibility (GoF)는 이 중 어느 것이든               │
│  구현할 수 있는 구조적 도구                                      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

2.3 학술적 출처

┌─────────────────────────────────────────────────────────────────┐
│                    핵심 문헌                                      │
│                                                                   │
│  1. GoF "Design Patterns" (1994)                                 │
│     ├── Gamma, Helm, Johnson, Vlissides                          │
│     ├── Chain of Responsibility 패턴 정의                        │
│     └── "Avoid coupling the sender of a request to its          │
│          receiver by giving more than one object a chance        │
│          to handle the request."                                 │
│                                                                   │
│  2. POSA1 "Pattern-Oriented Software Architecture" (1996)        │
│     └── Pipes and Filters 아키텍처 패턴                          │
│                                                                   │
│  3. POSA2 (2000년 9월)                                           │
│     ├── Schmidt, Stal, Rohnert, Buschmann                        │
│     ├── Interceptor를 아키텍처 패턴으로 공식 문서화              │
│     └── "Interceptor allows services to be added                │
│          transparently to a framework and triggered              │
│          automatically when certain events occur."               │
│                                                                   │
│  4. Core J2EE Patterns (2001)                                    │
│     └── "Intercepting Filter" 패턴 문서화                        │
│                                                                   │
│  POSA2 Interceptor의 핵심 특성 4가지:                            │
│  ├── 투명성 (Transparency)                                       │
│  ├── 런타임 동적 등록                                            │
│  ├── 이벤트 기반 트리거                                          │
│  └── 비침습적 (Non-invasive)                                     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

3. 개념이 나오게 된 배경: CGI의 문제

┌─────────────────────────────────────────────────────────────────┐
│              CGI 시대의 근본적 문제 (1993-1998)                   │
│                                                                   │
│  CGI란?                                                          │
│  ├── 1993년 NCSA의 Rob McCool이 명세 작성                        │
│  ├── Common Gateway Interface                                    │
│  └── 웹 서버가 외부 프로그램을 실행하여 동적 콘텐츠 생성        │
│                                                                   │
│  동작 방식:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  브라우저 ──► 웹서버 ──► fork() ──► CGI 스크립트 실행   │    │
│  │                              │                           │    │
│  │                              └── 요청마다 새 OS 프로세스 │    │
│  │                                  생성 → 처리 → 종료      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  문제: 크로스커팅 관심사의 코드 중복                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  login.cgi    → 인증 검사 코드 + 로깅 코드 + 비즈니스   │    │
│  │  order.cgi    → 인증 검사 코드 + 로깅 코드 + 비즈니스   │    │
│  │  profile.cgi  → 인증 검사 코드 + 로깅 코드 + 비즈니스   │    │
│  │  report.cgi   → 인증 검사 코드 + 로깅 코드 + 비즈니스   │    │
│  │  ...                                                     │    │
│  │  (100개 스크립트에 인증 로직 100번 복사!)                │    │
│  │                                                          │    │
│  │  인증 방식 변경되면? → 100개 파일 전부 수정              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  추가 문제:                                                      │
│  ├── 상태 비보존: 요청마다 프로세스가 죽으므로 상태 유지 불가    │
│  ├── 보안 취약성: 각 스크립트가 개별적으로 보안 처리              │
│  └── 성능: fork()는 비용이 매우 큰 시스템 콜                     │
│                                                                   │
│  1996년 FastCGI (Open Market):                                   │
│  ├── 프로세스 재사용으로 성능 문제 해결                          │
│  └── 그러나 코드 중복 문제는 여전!                               │
│                                                                   │
│  이 코드 중복 문제를 해결하기 위해                               │
│  Interceptor/Middleware/Filter 패턴이 등장                       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4. 역사적 진화 타임라인

4.1 전체 타임라인

┌─────────────────────────────────────────────────────────────────┐
│                    진화 타임라인                                   │
│                                                                   │
│  1993 ── CGI (NCSA, Rob McCool)                                  │
│    │     요청마다 프로세스 fork(), 코드 중복 만연                 │
│    │                                                              │
│  1994 ── GoF Chain of Responsibility                              │
│    │     Gamma, Helm, Johnson, Vlissides                          │
│    │     체인의 "하나"만 요청 처리 (순수 CoR)                    │
│    │                                                              │
│  1996 ── FastCGI (Open Market)                                    │
│    │     프로세스 재사용, 코드 중복은 미해결                     │
│    │     POSA1 Pipes and Filters 아키텍처 패턴                   │
│    │                                                              │
│  2000 ── POSA2 Interceptor 패턴 공식 문서화                      │
│    │     Schmidt, Stal, Rohnert, Buschmann                        │
│    │                                                              │
│  2001 ── Java Servlet 2.3 Filter (JSR-053)                       │
│    │     Danny Coward 주도, web.xml 선언적 필터 체인              │
│    │     Core J2EE Patterns "Intercepting Filter"                 │
│    │                                                              │
│  2002 ── WebWork/XWork 인터셉터                                   │
│    │     Rickard Oberg, Patrick Lightbody (OpenSymphony)          │
│    │     인터셉터 스택 개념                                       │
│    │                                                              │
│  2003 ── Spring Framework 0.9                                     │
│    │     Rod Johnson, HandlerInterceptor                          │
│    │     Django 프로젝트 시작 (Adrian Holovaty, Simon Willison)   │
│    │                                                              │
│  2004 ── Spring 1.0, Ruby on Rails 공개 (DHH)                    │
│    │     Rails before_filter, CoC 철학                            │
│    │                                                              │
│  2005 ── Rails 1.0, Django 공개                                   │
│    │                                                              │
│  2006 ── Struts 2 (XWork 인터셉터 흡수)                          │
│    │                                                              │
│  2007 ── Rack (Christian Neukirchen)                              │
│    │     Ruby 서버-프레임워크 표준 인터페이스                     │
│    │     Python WSGI (PEP 333, 2003)에서 영감                    │
│    │                                                              │
│  2009 ── ASP.NET MVC 1.0 (Scott Guthrie)                         │
│    │     속성(Attribute) 기반 Action Filter                       │
│    │                                                              │
│  2010 ── Express.js (TJ Holowaychuk)                              │
│    │     Connect + Express, next() 함수 체인                      │
│    │     Sinatra에서 영감                                         │
│    │                                                              │
│  2013 ── Koa.js (TJ Holowaychuk)                                  │
│    │     Generator → async/await 기반                             │
│    │     양파 모델(Onion Model) 도입                              │
│    │     Rails 4: before_filter → before_action 이름 변경         │
│    │                                                              │
│  2014 ── Express 4.0 (Connect 의존성 분리)                       │
│    │                                                              │
│  2016 ── gRPC 인터셉터 (Google)                                   │
│    │     4가지 타입: Unary/Streaming x 서버/클라이언트            │
│    │     Django 1.10: 신형 함수형 양파 모델                       │
│    │                                                              │
│  현재 ── 서비스 메시 (Envoy/Istio)                               │
│          코드 수정 없이 인프라 레벨 인터셉션                     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

4.2 주요 전환점 상세

Java Servlet Filter (2001)

┌─────────────────────────────────────────────────────────────────┐
│              Servlet Filter - 표준화된 필터 체인                  │
│                                                                   │
│  배경:                                                           │
│  ├── JSR-053, Danny Coward 주도                                  │
│  ├── 2000년 10월 Proposed Final Draft                            │
│  └── Servlet 2.3 이전: "서블릿 체이닝" 비공식 메커니즘 (비표준) │
│                                                                   │
│  핵심: web.xml에서 선언적으로 필터 체인 구성                     │
│                                                                   │
│  <!-- web.xml -->                                                │
│  <filter>                                                        │
│    <filter-name>AuthFilter</filter-name>                         │
│    <filter-class>com.example.AuthFilter</filter-class>           │
│  </filter>                                                       │
│  <filter-mapping>                                                │
│    <filter-name>AuthFilter</filter-name>                         │
│    <url-pattern>/*</url-pattern>                                 │
│  </filter-mapping>                                               │
│                                                                   │
│  동작 흐름:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  요청 ──► AuthFilter ──► LogFilter ──► Servlet          │    │
│  │                                                          │    │
│  │  각 Filter에서 FilterChain.doFilter() 호출으로           │    │
│  │  체인 실행 또는 중단 결정                                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  의의: 최초의 표준화된 웹 필터 메커니즘                          │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Spring MVC HandlerInterceptor (2003-2004)

┌─────────────────────────────────────────────────────────────────┐
│          Spring HandlerInterceptor vs Servlet Filter             │
│                                                                   │
│  Rod Johnson "Expert One-on-One J2EE Design and Development"     │
│  (2002.10) → Spring 0.9 (2003.6) → Spring 1.0 (2004.3)         │
│                                                                   │
│  Servlet Filter와의 핵심 차이:                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Servlet Filter:                                         │    │
│  │  ├── 서블릿 컨테이너 레벨 (Tomcat 등)                    │    │
│  │  ├── Spring Bean에 접근 어려움                           │    │
│  │  └── 모든 요청에 대해 동작                               │    │
│  │                                                          │    │
│  │  Spring HandlerInterceptor:                              │    │
│  │  ├── 프레임워크 레벨 (DispatcherServlet 내부)            │    │
│  │  ├── Spring Bean 완전 접근 가능                          │    │
│  │  ├── handler 객체로 컨트롤러 정보 접근                   │    │
│  │  └── ModelAndView 조작 가능                              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  실행 위치 비교:                                                 │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  요청 ──► [Servlet Filter] ──► DispatcherServlet        │    │
│  │                                    │                     │    │
│  │                              [HandlerInterceptor]        │    │
│  │                                    │                     │    │
│  │                               Controller                 │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Express.js 미들웨어 (2010)

┌─────────────────────────────────────────────────────────────────┐
│              Express.js - next()로 체인 제어                      │
│                                                                   │
│  TJ Holowaychuk, Connect + Express, Sinatra에서 영감             │
│                                                                   │
│  // Express 미들웨어 기본 구조                                   │
│  app.use((req, res, next) => {                                   │
│    console.log(`${req.method} ${req.url}`);                      │
│    next();  // 다음 미들웨어로 전달                              │
│  });                                                             │
│                                                                   │
│  app.use((req, res, next) => {                                   │
│    if (!req.headers.authorization) {                             │
│      return res.status(401).send('Unauthorized');                │
│      // next() 미호출 → 체인 중단                               │
│    }                                                             │
│    next();                                                       │
│  });                                                             │
│                                                                   │
│  핵심 특징:                                                      │
│  ├── next() 함수로 체인 진행/중단을 제어                         │
│  ├── 순서 = app.use() 호출 순서                                  │
│  ├── Express 4.0 (2014): Connect 의존성 완전 분리                │
│  └── JavaScript 생태계에서 "미들웨어"라는 용어를 대중화          │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5. 핵심 디자인 패턴

5.1 GoF Chain of Responsibility (1994)

┌─────────────────────────────────────────────────────────────────┐
│          Chain of Responsibility (GoF 1994)                      │
│                                                                   │
│  Intent:                                                         │
│  "Avoid coupling the sender of a request to its receiver        │
│   by giving more than one object a chance to handle             │
│   the request."                                                  │
│                                                                   │
│  원형 예시: GUI 컨텍스트 민감 도움말                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  사용자가 버튼 위에서 F1 누름                            │    │
│  │    │                                                     │    │
│  │    ▼                                                     │    │
│  │  Button ──(처리 못함)──► Panel ──(처리 못함)──► Dialog   │    │
│  │                                                  │        │    │
│  │                                           (도움말 표시!)  │    │
│  │                                                          │    │
│  │  핵심: 체인의 "오직 하나"만이 요청을 처리                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  UML 구조:                                                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Client ──► Handler (abstract)                           │    │
│  │               │  handleRequest()                         │    │
│  │               │  successor: Handler                      │    │
│  │               │                                          │    │
│  │         ┌─────┴──────┐                                   │    │
│  │         ▼            ▼                                   │    │
│  │  ConcreteHandler1  ConcreteHandler2                      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  적용 시점:                                                      │
│  ├── 처리 객체가 미리 알려져 있지 않을 때                        │
│  ├── 여러 객체 중 하나가 처리해야 할 때                          │
│  └── 처리 객체를 동적으로 변경하고 싶을 때                       │
│                                                                   │
│  결과:                                                           │
│  ├── 장점: 결합도 감소, 유연성 증가                              │
│  └── 단점: 처리 보장 없음 (체인 끝까지 아무도 안 처리할 수도)   │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.2 Pipes and Filters (POSA Vol.1, 1996)

┌─────────────────────────────────────────────────────────────────┐
│              Pipes and Filters 아키텍처 패턴                     │
│                                                                   │
│  구조:                                                           │
│  Data Source ──► Filter ──pipe──► Filter ──pipe──► Data Sink    │
│                                                                   │
│  가장 유명한 구현: Unix 파이프                                   │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  $ cat access.log | grep "ERROR" | sort | uniq -c       │    │
│  │                                                          │    │
│  │  cat ──► grep ──► sort ──► uniq                          │    │
│  │  (소스)  (필터)   (필터)   (싱크)                        │    │
│  │                                                          │    │
│  │  모든 필터가 데이터를 처리하고 다음으로 전달              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  CoR과의 핵심 차이:                                              │
│  ┌────────────────┬──────────────────┬────────────────────┐     │
│  │ 구분           │ Chain of Resp.   │ Pipes and Filters  │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 처리           │ 하나가 처리 후   │ 모든 필터가        │     │
│  │                │ 체인 중단        │ 데이터 처리        │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 패턴 수준      │ 객체 디자인 패턴 │ 아키텍처 패턴      │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 데이터 변환    │ 변환 없이 전달   │ 각 단계에서 변환   │     │
│  └────────────────┴──────────────────┴────────────────────┘     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.3 POSA2 Interceptor 패턴 (2000)

┌─────────────────────────────────────────────────────────────────┐
│              POSA2 Interceptor 패턴                               │
│                                                                   │
│  Douglas C. Schmidt의 ACE/TAO 프레임워크에서 발전               │
│  CORBA "Portable Interceptor" 표준에서 체계적 등장               │
│                                                                   │
│  정의:                                                           │
│  "Interceptor allows services to be added transparently         │
│   to a framework and triggered automatically when certain       │
│   events occur."                                                 │
│                                                                   │
│  GoF CoR과의 핵심 차이:                                          │
│  ┌────────────────┬──────────────────┬────────────────────┐     │
│  │ 구분           │ CoR (GoF 1994)   │ Interceptor        │     │
│  │                │                  │ (POSA2 2000)       │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 처리 주체      │ 체인 중 하나만   │ 모든 인터셉터가    │     │
│  │                │ 처리             │ 실행 보장          │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 등록 시점      │ 주로 컴파일 타임 │ 런타임 동적 등록   │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 대상           │ 범용 요청 라우팅 │ 프레임워크 확장    │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ 투명성         │ 명시적 체인 구성 │ 나머지 시스템에    │     │
│  │                │                  │ 투명               │     │
│  └────────────────┴──────────────────┴────────────────────┘     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

5.4 패턴 계보도

┌─────────────────────────────────────────────────────────────────┐
│                    패턴 계보도                                    │
│                                                                   │
│  GoF Chain of Responsibility (1994)                              │
│  │  순수 CoR: 하나만 처리, 나머지 무시                           │
│  │                                                               │
│  ├── Pipeline 변형 (모두 실행)                                   │
│  │   │                                                           │
│  │   ├── POSA1 Pipes and Filters (1996)                          │
│  │   │   아키텍처 패턴, Unix 파이프                              │
│  │   │                                                           │
│  │   ├── POSA2 Interceptor (2000)                                │
│  │   │   프레임워크 확장, 투명성/동적 등록                       │
│  │   │                                                           │
│  │   └── Middleware Pattern (2010~)                               │
│  │       Express.js가 대중화한 웹 프레임워크 패턴                │
│  │                                                               │
│  └── 현대적 확장                                                 │
│      │                                                           │
│      ├── 리액티브: Spring WebFlux WebFilter                      │
│      │   Mono<Void> 기반 논블로킹 체인                           │
│      │                                                           │
│      └── 인프라: Envoy/Istio 사이드카                            │
│          코드 수정 없이 인프라 레벨 인터셉션                     │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6. 작동 원리

6.1 기본 구조: 체인 실행

┌─────────────────────────────────────────────────────────────────┐
│              인터셉터/미들웨어 기본 동작                          │
│                                                                   │
│  선형 모델 (Express.js 스타일):                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  요청 ──► [MW1] ──► [MW2] ──► [MW3] ──► 핸들러          │    │
│  │            │         │         │                         │    │
│  │           로깅      인증      압축                       │    │
│  │                                                          │    │
│  │  각 미들웨어에서 next() 호출 → 다음으로 전달             │    │
│  │  next() 미호출 → 체인 중단 (예: 인증 실패 시)            │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  양파 모델 (Koa.js 스타일):                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │          ┌───────────────────────────────┐               │    │
│  │          │  MW1 (before)                 │               │    │
│  │          │  ┌───────────────────────┐    │               │    │
│  │          │  │  MW2 (before)         │    │               │    │
│  │          │  │  ┌───────────────┐    │    │               │    │
│  │  요청 ──►│  │  │   핸들러      │    │    │──► 응답       │    │
│  │          │  │  └───────────────┘    │    │               │    │
│  │          │  │  MW2 (after)          │    │               │    │
│  │          │  └───────────────────────┘    │               │    │
│  │          │  MW1 (after)                  │               │    │
│  │          └───────────────────────────────┘               │    │
│  │                                                          │    │
│  │  await next() 전 = preHandle (요청 가공)                 │    │
│  │  await next() 후 = postHandle (응답 가공)                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6.2 Koa.js 양파 모델 코드 예시

// Koa.js 양파 모델 - 요청과 응답이 동일 계층을 통과

app.use(async (ctx, next) => {
  const start = Date.now();           // ① 요청 들어올 때
  await next();                        // ② 다음 미들웨어로
  const ms = Date.now() - start;      // ⑤ 응답 나올 때
  ctx.set('X-Response-Time', `${ms}ms`);
});

app.use(async (ctx, next) => {
  console.log('요청 시작');           // ③ 요청 들어올 때
  await next();                        // → 핸들러 실행
  console.log('응답 완료');           // ④ 응답 나올 때
});

// 실행 순서: ① → ② → ③ → 핸들러 → ④ → ⑤
┌─────────────────────────────────────────────────────────────────┐
│              koa-compose 내부 구현 원리                           │
│                                                                   │
│  function compose(middleware) {                                   │
│    return function(context, next) {                              │
│      let index = -1;                                             │
│      return dispatch(0);                                         │
│                                                                   │
│      function dispatch(i) {                                      │
│        index = i;                                                │
│        let fn = middleware[i];                                    │
│        if (i === middleware.length) fn = next;                    │
│        if (!fn) return Promise.resolve();                        │
│        return fn(context, () => dispatch(i + 1));                │
│      }                                                           │
│    };                                                            │
│  }                                                               │
│                                                                   │
│  핵심: 재귀적 dispatch 함수가 양파 모델을 구현                   │
│  next()를 호출하면 dispatch(i+1)이 실행되어 다음 계층으로        │
│  await로 기다렸다가 돌아오면 나머지 코드(after) 실행             │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

6.3 Spring HandlerInterceptor 생명주기

// Spring HandlerInterceptor 3단계 생명주기

public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
        // 컨트롤러 실행 전
        // false 반환 시 체인 중단
        log.info("요청: {} {}", request.getMethod(), request.getRequestURI());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) {
        // 컨트롤러 실행 후, 뷰 렌더링 전
        // ModelAndView 조작 가능
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) {
        // 뷰 렌더링 완료 후 (리소스 정리)
    }
}

7. 장점

┌─────────────────────────────────────────────────────────────────┐
│              Interceptor/Middleware의 7가지 장점                  │
│                                                                   │
│  1. 관심사의 분리 (Separation of Concerns)                       │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Before: 컨트롤러 안에 인증+로깅+압축+비즈니스 혼재     │    │
│  │  After:  인프라 관심사를 비즈니스 로직에서 완전 격리     │    │
│  │                                                          │    │
│  │  컨트롤러는 비즈니스 로직에만 집중                       │    │
│  │  인증/로깅/압축은 미들웨어가 처리                        │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  2. DRY 원칙 (Don't Repeat Yourself)                             │
│  ├── 100개 엔드포인트에 JWT 검증 코드를 100번 쓸 필요 없음      │
│  └── 미들웨어 하나로 전체 적용                                   │
│                                                                   │
│  3. 개방-폐쇄 원칙 (Open-Closed Principle)                       │
│  ├── 기존 코드를 변경하지 않고                                   │
│  └── 새로운 인터셉터를 체인에 추가                               │
│                                                                   │
│  4. 조합 가능성 (Composability)                                   │
│  ├── 모노이드 구조: 인터셉터 + 인터셉터 = 인터셉터              │
│  └── 순서에 따라 자유롭게 조합                                   │
│                                                                   │
│  5. 테스트 가능성 (Testability)                                   │
│  ├── 각 인터셉터를 독립적으로 단위 테스트 가능                   │
│  └── Mock 요청/응답으로 격리된 테스트                             │
│                                                                   │
│  6. 단일 책임 원칙 (Single Responsibility)                        │
│  ├── 인증 미들웨어: 인증만                                       │
│  ├── 로깅 미들웨어: 로깅만                                       │
│  └── 압축 미들웨어: 압축만                                       │
│                                                                   │
│  7. 투명성/비침투성 (Transparency)                                │
│  ├── 비즈니스 로직은 인터셉터 존재를 모름                        │
│  └── 나머지 시스템에 영향 없이 추가/제거                         │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

8. 단점과 한계

┌─────────────────────────────────────────────────────────────────┐
│              6가지 단점과 한계                                    │
│                                                                   │
│  1. 비가시적 제어 흐름                                           │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  "내 요청이 어디서 막혔지?"                              │    │
│  │                                                          │    │
│  │  요청 ──► [?] ──► [?] ──► [?] ──► [?] ──► 핸들러       │    │
│  │           어디서 401이 나오는 거지...?                    │    │
│  │                                                          │    │
│  │  Ben Nadel:                                              │    │
│  │  "HTTP 인터셉터는 본질적으로 공유된 전역 상태"           │    │
│  │                                                          │    │
│  │  Richard Marmorstein "Beware Middleware":                 │    │
│  │  "정적 분석 도구가 거의 도움이 안 된다"                  │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  2. 순서 의존성 버그                                             │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  올바른 순서:                                            │    │
│  │  Authentication ──► Authorization ──► RateLimit          │    │
│  │  (누구인지 확인)    (권한 확인)       (요청 제한)        │    │
│  │                                                          │    │
│  │  잘못된 순서:                                            │    │
│  │  Authorization ──► Authentication ──► RateLimit          │    │
│  │  (권한 확인?)       (누군지도 모르는데?)                  │    │
│  │  → 모든 요청 401! 에러 없이 조용히 잘못된 동작!         │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  3. 성능 오버헤드 ("미들웨어 세금")                              │
│  ├── 모든 요청이 전체 체인을 통과                                │
│  ├── 각 미들웨어의 실행 시간이 누적                              │
│  └── Vercel 사례: 요청당 60-70ms 추가 지연 발생                  │
│                                                                   │
│  4. 전역 vs 로컬 스코프 문제                                     │
│  ├── 전역 미들웨어가 불필요한 경로에도 적용                      │
│  ├── /health 체크에도 인증 미들웨어 실행                         │
│  └── 예외 경로 관리가 복잡해짐                                   │
│                                                                   │
│  5. 숨겨진 결합 (Hidden Coupling)                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  // RateLimit 미들웨어                                   │    │
│  │  if (req.isAdmin) {  // 어디서 설정한 거지?              │    │
│  │    limit = 1000;     // Auth 미들웨어에서 설정했나?      │    │
│  │  }                   // 의존 관계가 코드에 명시 안 됨!   │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  6. 체인 전체 테스트의 복잡성                                    │
│  ├── 개별 미들웨어 단위 테스트는 쉬움                            │
│  ├── 체인 전체의 상호작용 테스트는 통합 테스트 필요              │
│  └── 순서 의존성까지 검증하려면 테스트가 복잡해짐                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

9. 안티패턴

┌─────────────────────────────────────────────────────────────────┐
│              5가지 안티패턴                                       │
│                                                                   │
│  1. 전지전능 인터셉터 (God Interceptor)                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  // 하나의 미들웨어가 모든 것을 처리                     │    │
│  │  app.use((req, res, next) => {                           │    │
│  │    // 인증 검사                                          │    │
│  │    // 권한 검사                                          │    │
│  │    // 로깅                                               │    │
│  │    // 입력 검증                                          │    │
│  │    // CORS 처리                                          │    │
│  │    // 레이트 리밋                                        │    │
│  │    // 캐싱                                               │    │
│  │    // ... 500줄                                          │    │
│  │    next();                                               │    │
│  │  });                                                     │    │
│  │                                                          │    │
│  │  → 단일 책임 원칙 위반, 테스트/유지보수 불가능           │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  2. 인터셉터 수프 (Interceptor Soup)                             │
│  ├── 미들웨어가 30개, 40개 쌓여서 흐름 파악 불가                 │
│  ├── 어떤 미들웨어가 어떤 영향을 주는지 추적 어려움              │
│  └── 디버깅 시 "수프 속에서 바늘 찾기"                           │
│                                                                   │
│  3. 비즈니스 로직의 인터셉터화                                   │
│  ├── 횡단 관심사만 미들웨어에 적합                               │
│  ├── 비즈니스 규칙을 미들웨어에 넣으면 로직이 숨겨짐             │
│  └── "왜 이 주문이 거부됐지?" → 미들웨어 20개를 뒤져야          │
│                                                                   │
│  4. 상태 저장 인터셉터 (Stateful Interceptor)                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  let requestCount = 0;  // 인터셉터에 상태 보관          │    │
│  │                                                          │    │
│  │  app.use((req, res, next) => {                           │    │
│  │    requestCount++;      // 동시 요청에서 레이스 컨디션!  │    │
│  │    next();                                               │    │
│  │  });                                                     │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  5. 필터 간 정보 과다 공유                                       │
│  ├── req 객체에 임의 속성을 과도하게 부착                        │
│  ├── req.user, req.isAdmin, req.tenant, req.featureFlags...      │
│  └── 미들웨어 간 암묵적 계약이 되어 결합도 상승                  │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

10. 대안 비교

┌─────────────────────────────────────────────────────────────────┐
│          Interceptor/Middleware의 4가지 대안                      │
│                                                                   │
│  1. AOP (Aspect-Oriented Programming)                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  특징:                                                   │    │
│  │  ├── 임의 메서드에 정밀 적용 (HTTP 경계 밖에서도)        │    │
│  │  ├── 타입 안전 (컴파일 타임 위빙)                        │    │
│  │  └── 포인트컷으로 적용 대상 세밀 지정                    │    │
│  │                                                          │    │
│  │  적합한 경우:                                            │    │
│  │  ├── HTTP 요청/응답이 아닌 일반 메서드에 적용할 때       │    │
│  │  ├── 트랜잭션 관리, 캐싱, 메서드 레벨 보안              │    │
│  │  └── Spring @Transactional이 대표적 AOP 활용             │    │
│  │                                                          │    │
│  │  vs Interceptor:                                         │    │
│  │  인터셉터는 HTTP 경계에서 동작, AOP는 어디서든 동작      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  2. 데코레이터 패턴 (Decorator Pattern)                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  특징:                                                   │    │
│  │  ├── 특정 객체 인스턴스를 래핑                           │    │
│  │  ├── 코드에서 명확히 보임 (명시적)                       │    │
│  │  └── 체인이 아닌 중첩 구조                               │    │
│  │                                                          │    │
│  │  // 데코레이터: 누가 래핑했는지 코드에서 보임            │    │
│  │  service = new LoggingDecorator(                          │    │
│  │              new CachingDecorator(                        │    │
│  │                new RealService()));                       │    │
│  │                                                          │    │
│  │  vs Interceptor:                                         │    │
│  │  데코레이터는 명시적, 인터셉터는 투명                    │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  3. 이벤트 드리븐 / 옵저버 패턴                                 │
│  ├── 비동기 브로드캐스트, 느슨한 결합                            │
│  ├── 요청/응답 체인이 아닌 발행/구독 모델                        │
│  └── 적합: 알림, 감사 로그 등 비동기 처리                        │
│                                                                   │
│  4. 직접 합성 (함수형 접근)                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  // 명시적 매개변수와 반환값                             │    │
│  │  const result = compress(                                │    │
│  │                   authorize(                             │    │
│  │                     authenticate(request)));             │    │
│  │                                                          │    │
│  │  장점: 타입 안전, 흐름이 코드에서 명확히 보임            │    │
│  │  단점: 규모가 커지면 관리 어려움                         │    │
│  │  적합: 소규모 앱, 단순한 파이프라인                      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  요약 비교:                                                      │
│  ┌───────────┬──────────────┬────────────┬──────────────┐       │
│  │ 대안      │ 투명성       │ 적용 범위  │ 타입 안전성  │       │
│  ├───────────┼──────────────┼────────────┼──────────────┤       │
│  │ AOP       │ 높음         │ 임의 메서드│ 높음         │       │
│  │ Decorator │ 낮음(명시적) │ 특정 객체  │ 높음         │       │
│  │ Observer  │ 높음         │ 이벤트     │ 중간         │       │
│  │ 함수 합성│ 낮음(명시적) │ 전체       │ 매우 높음    │       │
│  │ 미들웨어 │ 높음         │ HTTP 경계  │ 낮음         │       │
│  └───────────┴──────────────┴────────────┴──────────────┘       │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11. 현대적 변형

11.1 Koa.js 양파 모델 (2013)

┌─────────────────────────────────────────────────────────────────┐
│              Koa.js 양파 모델                                     │
│                                                                   │
│  TJ Holowaychuk, Generator → async/await 기반                    │
│                                                                   │
│  Express와의 차이:                                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Express (선형):                                         │    │
│  │  요청 ──► MW1 ──► MW2 ──► MW3 ──► 핸들러 ──► 응답      │    │
│  │  (요청 방향으로만 진행)                                  │    │
│  │                                                          │    │
│  │  Koa (양파):                                             │    │
│  │  요청 ──► MW1.전 ──► MW2.전 ──► 핸들러                  │    │
│  │  응답 ◄── MW1.후 ◄── MW2.후 ◄──┘                       │    │
│  │  (요청/응답이 동일 계층을 왕복 통과)                     │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  이점:                                                           │
│  ├── 한 미들웨어 안에서 요청 전/후 처리를 모두 작성              │
│  ├── 응답 시간 측정이 자연스러움 (start → next → end)            │
│  └── 에러 처리가 try/catch로 직관적                              │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11.2 Spring WebFlux WebFilter (리액티브)

┌─────────────────────────────────────────────────────────────────┐
│              Spring WebFlux WebFilter                             │
│                                                                   │
│  Mono<Void> 기반 논블로킹 필터 체인                              │
│                                                                   │
│  @Component                                                      │
│  public class LogFilter implements WebFilter {                   │
│      @Override                                                   │
│      public Mono<Void> filter(ServerWebExchange exchange,        │
│                               WebFilterChain chain) {            │
│          log.info("요청: {}", exchange.getRequest().getPath());   │
│          return chain.filter(exchange)                            │
│                      .doOnSuccess(v -> log.info("완료"));        │
│      }                                                           │
│  }                                                               │
│                                                                   │
│  기존 Servlet Filter와의 차이:                                   │
│  ├── 블로킹 없이 비동기 체인 실행                                │
│  ├── Reactor 스트림 안에서 자연스럽게 조합                       │
│  └── 논블로킹 I/O와 완벽 호환                                    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11.3 gRPC 인터셉터 (2016)

┌─────────────────────────────────────────────────────────────────┐
│              gRPC 인터셉터                                        │
│                                                                   │
│  Google 공개, HTTP가 아닌 RPC 프로토콜에서의 인터셉션            │
│                                                                   │
│  4가지 타입:                                                     │
│  ┌────────────────┬──────────────────┬────────────────────┐     │
│  │                │ 서버 (Server)    │ 클라이언트 (Client)│     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ Unary          │ UnaryServer      │ UnaryClient        │     │
│  │ (단일 요청)    │ Interceptor      │ Interceptor        │     │
│  ├────────────────┼──────────────────┼────────────────────┤     │
│  │ Streaming      │ StreamServer     │ StreamClient       │     │
│  │ (스트리밍)     │ Interceptor      │ Interceptor        │     │
│  └────────────────┴──────────────────┴────────────────────┘     │
│                                                                   │
│  특징:                                                           │
│  ├── 양방향 스트리밍 지원                                        │
│  ├── 메타데이터(HTTP 헤더 대응) 조작                             │
│  └── 서버/클라이언트 양쪽 모두에서 인터셉션 가능                 │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

11.4 서비스 메시 사이드카 (Envoy/Istio)

┌─────────────────────────────────────────────────────────────────┐
│              서비스 메시: 인프라 레벨 인터셉션                    │
│                                                                   │
│  POSA2 Interceptor의 궁극적 진화                                 │
│  "코드 수정 없이" 인프라 레벨에서 모든 것을 가로채기             │
│                                                                   │
│  동작 방식:                                                      │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  서비스 A                        서비스 B               │    │
│  │  ┌──────────┐  ┌──────────┐     ┌──────────┐           │    │
│  │  │   App    │──│  Envoy   │─────│  Envoy   │──│ App │  │    │
│  │  │          │  │ (Sidecar)│     │ (Sidecar)│  │     │  │    │
│  │  └──────────┘  └──────────┘     └──────────┘  └─────┘  │    │
│  │                                                          │    │
│  │  iptables로 모든 트래픽을 Envoy 프록시로 리다이렉트     │    │
│  │  앱은 Envoy의 존재를 모름 (완벽한 투명성)               │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  제공 기능 (코드 변경 없이):                                     │
│  ├── mTLS (상호 TLS 인증)                                        │
│  ├── 로드밸런싱                                                  │
│  ├── 서킷브레이커                                                │
│  ├── 재시도 (Retry)                                              │
│  ├── 분산 트레이싱                                               │
│  └── 트래픽 관찰 (Observability)                                 │
│                                                                   │
│  의의:                                                           │
│  인터셉터 패턴이 코드 레벨 → 프레임워크 레벨 → 인프라 레벨로    │
│  진화한 최종 형태                                                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

12. 실무 교훈과 장애 사례

┌─────────────────────────────────────────────────────────────────┐
│              실제 장애 사례와 교훈                                │
│                                                                   │
│  사례 1: "4시간짜리 한 줄 수정"                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  증상: 특정 API에서 간헐적으로 403 Forbidden 반환        │    │
│  │  원인: 미들웨어 순서가 뒤바뀌어 있었음                   │    │
│  │        Authorization이 Authentication보다 먼저 실행      │    │
│  │  수정: 미들웨어 등록 순서 한 줄 변경                     │    │
│  │  소요: 원인 파악에 4시간                                 │    │
│  │                                                          │    │
│  │  교훈: 순서 의존성 버그는 에러 없이 조용히 발생하므로    │    │
│  │        디버깅이 매우 어렵다                               │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  사례 2: Angular "부족 지식 문제"                                │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  증상: 새로 합류한 팀원이 HTTP 인터셉터 동작을           │    │
│  │        이해하지 못해 같은 로직을 서비스에 중복 구현       │    │
│  │  원인: 인터셉터는 코드에서 명시적으로 보이지 않아         │    │
│  │        존재 자체를 파악하기 어려움                        │    │
│  │                                                          │    │
│  │  교훈: 인터셉터의 투명성은 장점이자 단점                  │    │
│  │        팀 전체가 아키텍처를 공유해야 함                   │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  사례 3: ASP.NET 스트림 재진입 문제                              │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  증상: 미들웨어에서 Request Body를 읽은 후               │    │
│  │        다음 미들웨어/핸들러에서 빈 본문                   │    │
│  │  원인: HTTP 요청 스트림은 한 번만 읽을 수 있음           │    │
│  │        (Stream이 소진되면 되감기 필요)                    │    │
│  │  수정: EnableBuffering()으로 스트림 재읽기 허용           │    │
│  │                                                          │    │
│  │  교훈: 미들웨어 간 공유 자원(스트림 등) 관리에 주의      │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  사례 4: Vercel "60-70ms 미들웨어 세금"                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  증상: 모든 요청에 60-70ms 지연 추가                     │    │
│  │  원인: Edge Middleware가 모든 요청을 거침                 │    │
│  │  영향: 사용자 체감 성능 저하                              │    │
│  │                                                          │    │
│  │  교훈: 미들웨어는 "무료"가 아님                           │    │
│  │        적용 범위를 신중하게 제한해야 함                   │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  사례 5: NestJS 생명주기 복잡성                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  NestJS 요청 처리 순서:                                  │    │
│  │  Middleware → Guard → Interceptor(전) → Pipe →          │    │
│  │  Handler → Interceptor(후) → ExceptionFilter            │    │
│  │                                                          │    │
│  │  증상: 각 계층의 역할과 실행 순서 혼동으로               │    │
│  │        로직이 잘못된 계층에 배치                          │    │
│  │                                                          │    │
│  │  교훈: 프레임워크의 생명주기를 정확히 이해하고           │    │
│  │        각 계층에 적합한 책임만 부여해야 함                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

13. 의사결정 가이드

┌─────────────────────────────────────────────────────────────────┐
│          "Interceptor/Middleware를 사용해야 할까?"                │
│                                                                   │
│  Step 1: 횡단 관심사인가?                                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  횡단 관심사 (미들웨어 적합):                            │    │
│  │  ├── 인증/인가 (Authentication/Authorization)            │    │
│  │  ├── 요청/응답 로깅                                      │    │
│  │  ├── CORS 처리                                           │    │
│  │  ├── 압축 (gzip)                                         │    │
│  │  ├── 레이트 리밋                                         │    │
│  │  ├── 요청 ID 부여 (트레이싱)                             │    │
│  │  └── 에러 핸들링                                         │    │
│  │                                                          │    │
│  │  비즈니스 로직 (미들웨어 부적합):                        │    │
│  │  ├── 주문 검증 규칙                                      │    │
│  │  ├── 할인 계산                                           │    │
│  │  ├── 재고 확인                                           │    │
│  │  └── 비즈니스 이벤트 처리                                │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Step 2: 적용 범위는?                                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  전체 엔드포인트 → 전역 미들웨어                         │    │
│  │  특정 경로 그룹  → 라우트 레벨 미들웨어                  │    │
│  │  특정 메서드     → AOP 또는 데코레이터 고려              │    │
│  │  HTTP 밖에서도   → AOP 선택                              │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  Step 3: 어떤 메커니즘을 선택할까?                               │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  Spring 생태계:                                          │    │
│  │  ├── 인코딩/보안 등 저수준 → Servlet Filter             │    │
│  │  ├── 컨트롤러 전후 처리   → HandlerInterceptor          │    │
│  │  ├── 메서드 레벨 관심사   → AOP (@Aspect)               │    │
│  │  └── 리액티브 스택       → WebFilter                     │    │
│  │                                                          │    │
│  │  Node.js 생태계:                                         │    │
│  │  ├── 전역 관심사         → app.use() 미들웨어            │    │
│  │  ├── 라우트별 관심사     → 라우트 미들웨어               │    │
│  │  └── 응답 가공 필요 시   → Koa 양파 모델                 │    │
│  │                                                          │    │
│  │  마이크로서비스:                                         │    │
│  │  ├── 서비스 간 공통 관심사 → 서비스 메시 (Istio/Envoy)  │    │
│  │  └── gRPC 통신            → gRPC 인터셉터               │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
│  체크리스트:                                                     │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                                                          │    │
│  │  미들웨어 도입 전 확인:                                  │    │
│  │  [ ] 횡단 관심사인가? (비즈니스 로직이 아닌가?)          │    │
│  │  [ ] 순서 의존성이 문서화되어 있는가?                    │    │
│  │  [ ] 성능 영향을 측정했는가?                             │    │
│  │  [ ] 전역/로컬 스코프를 적절히 설정했는가?               │    │
│  │  [ ] 미들웨어 간 숨겨진 결합은 없는가?                   │    │
│  │  [ ] 팀 전체가 미들웨어 체인을 이해하고 있는가?          │    │
│  │                                                          │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

14. 참고 자료

┌─────────────────────────────────────────────────────────────────┐
│                    참고 자료                                      │
│                                                                   │
│  학술 문헌:                                                      │
│  ├── Gamma, Helm, Johnson, Vlissides                             │
│  │   "Design Patterns: Elements of Reusable Object-Oriented     │
│  │    Software" (1994) - Chain of Responsibility                 │
│  │                                                               │
│  ├── Buschmann, Meunier, Rohnert, Sommerlad, Stal               │
│  │   "Pattern-Oriented Software Architecture Vol.1" (1996)       │
│  │   - Pipes and Filters                                         │
│  │                                                               │
│  ├── Schmidt, Stal, Rohnert, Buschmann                           │
│  │   "Pattern-Oriented Software Architecture Vol.2" (2000)       │
│  │   - Interceptor Pattern                                       │
│  │                                                               │
│  ├── Alur, Crupi, Malks                                          │
│  │   "Core J2EE Patterns" (2001) - Intercepting Filter           │
│  │                                                               │
│  └── Rod Johnson                                                 │
│      "Expert One-on-One J2EE Design and Development" (2002)      │
│                                                                   │
│  표준 명세:                                                      │
│  ├── JSR-053: Java Servlet 2.3 (Danny Coward, 2000-2001)        │
│  ├── PEP 333: Python WSGI (2003)                                 │
│  └── CORBA Portable Interceptor Specification                    │
│                                                                   │
│  프레임워크 역사:                                                │
│  ├── Express.js - TJ Holowaychuk (2010)                          │
│  ├── Koa.js - TJ Holowaychuk (2013)                              │
│  ├── Ruby on Rails - DHH (2004)                                  │
│  ├── Django - Adrian Holovaty, Simon Willison (2003/2005)        │
│  ├── Spring Framework - Rod Johnson (2003/2004)                  │
│  ├── ASP.NET MVC - Scott Guthrie (2007/2009)                    │
│  ├── Rack - Christian Neukirchen (2007)                          │
│  ├── WebWork/XWork - Rickard Oberg, Patrick Lightbody (2002)    │
│  └── gRPC - Google (2016)                                        │
│                                                                   │
│  비평 및 분석:                                                   │
│  ├── Ben Nadel - HTTP 인터셉터의 전역 상태 문제 분석             │
│  ├── Richard Marmorstein - "Beware Middleware"                    │
│  └── Vercel - Edge Middleware 성능 이슈 사례                     │
│                                                                   │
│  어원 자료:                                                      │
│  ├── intercipere (라틴어) - inter- + capere                      │
│  ├── Proto-Indo-European *kap- "붙잡다"                          │
│  ├── 영어 interceptor 최초 기록: 1590년대                        │
│  └── "Middleware" 최초 사용: 1968 NATO Software Engineering      │
│      Conference (Alex d'Agapeyeff)                                │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘