개발이군고구마

모바일 HTTP 이미지 요청과 /runtime/exception 추적 정리 본문

SERVER/Architecture

모바일 HTTP 이미지 요청과 /runtime/exception 추적 정리

김구황 2026. 3. 18. 07:55
728x90
운영 이슈 분석 메모 · 이미지 반영 최종본

모바일 HTTP 이미지 요청과 /runtime/exception 원인 정리

목차

  1. 문제 배경
  2. 이번에 확인된 구조
  3. 문제와 원인
  4. 리다이렉트가 일어나는 지점
  5. 핵심 원리: 요청한 쪽이 응답도 받는다
  6. 보안 그룹, NACL, NAT 관점
  7. 실제 패킷 흐름
  8. 코드 레벨에서 예외가 나는 이유
  9. 최종 정리

1. 문제 배경

운영 중인 사이트의 상품 상세 페이지에서 이미지는 아래와 같은 형태로 로드된다.

<img src="https://aromacomall.imghost.cafe24.com/ac/ac_cactus.jpg">

제니퍼에서는 지속적으로 /runtime/exception 호출 예외가 보였고, 추적해보니 일부 모바일 요청에서 이미지 URL이 HTTP로 시작하는 케이스가 있었다. 브라우저 콘솔에서는 이 요청이 301 또는 302로 HTTPS로 전환되는 것도 확인했다.

2. 이번에 확인된 구조

확인된 구조
Cloudgateway는 추상적인 개념이 아니라 실제로 존재하는 프록시 서버이며, Web ALB 뒤의 Target Group 중 하나로 붙어 있다. Web ALB는 경로에 따라 Cloudgateway 또는 이미지 정적 경로 또는 WAS 쪽으로 요청을 분기한다.
  • 사실Cloudgateway는 외부 인터넷으로 나가는 프록시 역할을 수행한다.
  • 사실흐름은 대체로 Cloudgateway → NAT 고정 IP → 외부 인터넷 서버 형태다.
  • 사실Cloudgateway는 Web ALB 뒤의 Target Group으로 존재한다.
  • 사실Web ALB는 path 등에 따라 Cloudgateway / 이미지 정적 경로 / WAS로 요청을 보낸다.

3. 문제와 원인

3-1. 현재 발생하고 있는 흐름

현재 발생 중인 흐름

문제의 핵심은 브라우저가 직접 외부 404를 받는 구조가 아니라, 내부 경로가 Cloudgateway를 통해 외부 서버를 호출하고 그 404 응답을 내부 코드가 받는다는 점이다.

3-2. 원인 요약

요약
HTML 안의 HTTP 이미지 URL이 출발점이 되었고, 그 요청은 HTTPS로 전환된 뒤 Web ALB의 규칙에 의해 Cloudgateway Target Group으로 분기되었다. Cloudgateway는 외부 이미지 서버를 호출했고, 외부 서버는 404를 반환했다. 이후 그 404 응답을 받은 내부 코드가 예외로 처리하면서 /runtime/exception 로그가 적재된 것으로 보는 설명이 가장 자연스럽다.

4. 리다이렉트가 일어나는 지점

브라우저 단계에서 HTTP 이미지 URL을 발견하고 HTTPS로 리다이렉트되는 흐름은 분명하다. 여기서 중요한 점은 리다이렉트는 브라우저가 먼저 경험하는 프론트 요청 흐름이고, 그 뒤 내부에서 Cloudgateway 경로를 타는 것은 서버사이드 처리 흐름일 수 있다는 점이다.

4-1. 브라우저가 보는 리다이렉트 흐름

브라우저 리다이렉트 흐름

4-2. 코드 관점의 리다이렉트 예시

리다이렉트는 여러 레이어에서 걸 수 있다. 다만 지금 구조에서는 브라우저에서 301, 302를 확인했기 때문에, 아래와 같은 프론트 레이어 설정이 있을 가능성이 높다.

# Nginx 예시
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}
# Spring MVC 예시
@GetMapping("/image")
public String redirectToHttps() {
    return "redirect:https://example.com/image";
}
# CDN rule 개념 예시
if (scheme == "http") {
    redirect(301, "https://" + host + request_uri);
}

5. 핵심 원리: 요청한 쪽이 응답도 받는다

가장 중요한 포인트는 TCP 소켓은 요청한 쪽이 응답도 받는다는 것이다. 즉 WAS가 먼저 외부로 TCP 연결을 열었다면, 외부에서 오는 404 응답은 새로운 인바운드 요청이 아니라 기존 아웃바운드 세션의 응답 패킷이다.

5-1. TCP 소켓 관점의 흐름

TCP 소켓 흐름
WAS (PRD VPC 내부)
  1) 외부로 TCP 연결 시작
     -> NAT Gateway 또는 공인 IP를 통해 외부로 나감

외부 이미지 서버
  2) 404 응답 반환
     -> 새 요청처럼 보이지만, 실제로는 1)에서 열린 TCP 세션의 응답

WAS
  3) 동일 소켓으로 404 응답 수신
     -> 내부 예외 처리

6. 보안 그룹, NACL, NAT 관점

외부 응답이 VPC 안으로 들어오는 것이 가능하냐는 질문에 대한 답은 가능하다. 단, 새로운 인바운드가 아니라 Return Traffic이기 때문이다.

6-1. 보안/네트워크 관점 다이어그램

보안 그룹과 NAT 흐름
구분 동작 방식 외부 응답 허용 여부
Security Group Stateful. Outbound 허용 시 해당 세션의 응답은 자동 허용 자동 허용
NACL Stateless. Inbound와 Outbound를 각각 고려해야 함 Ephemeral Port 범위 허용 시 통과
NAT Gateway 세션 테이블로 Outbound 연결을 추적하고 응답을 자동 매핑 자동 처리
핵심
WAS가 먼저 연결을 열었기 때문에, 외부에서 오는 404 응답은 새로운 인바운드 요청이 아니라 기존 아웃바운드 연결의 응답 패킷이다. 그래서 Imperva를 다시 거치지 않고 WAS까지 돌아올 수 있다.

7. 실제 패킷 흐름

7-1. 실제 패킷 흐름 다이어그램

실제 패킷 흐름 다이어그램
[WAS 서버]
1) connect(외부IP:443) -> TCP SYN 전송
   출발지: WAS 사설IP:ephemeral_port

[NAT Gateway]
2) SNAT 처리
   사설IP:포트 -> 공인IP:포트
   세션 테이블 매핑 기록

[외부 이미지 서버]
3) 요청 처리 후 404 응답
   목적지: 공인IP:포트

[NAT Gateway]
4) DNAT 처리
   공인IP:포트 -> 사설IP:포트 복원

[WAS 서버]
5) 동일 소켓으로 404 응답 수신
   -> HttpClientErrorException(404) 가능
   -> /runtime/exception 로그 적재 가능

8. 코드 레벨에서 예외가 나는 이유

404 자체는 정상적인 HTTP 응답이지만, 서버사이드 코드가 이를 어떻게 처리하느냐에 따라 예외가 날 수 있다. 이미지에서 정리된 시나리오 A는 WAS가 서버사이드에서 직접 이미지를 fetch 하는 경우로 볼 수 있다.

8-1. 서버사이드 fetch 흐름

WAS (JSP or Spring) 내부 코드
  -> 이미지 URL을 서버사이드에서 직접 HTTP 호출
  -> 해당 호출이 Cloudgateway TG를 통해 외부로 나감
  -> 외부 서버가 404 응답
  -> WAS 코드가 404를 받아 Exception 처리
  -> /runtime/exception 로그 발생

8-2. 예외가 발생할 수 있는 코드 예시

// RestTemplate 예시
try {
    ResponseEntity<byte[]> res =
        restTemplate.getForEntity(imageUrl, byte[].class);
} catch (HttpClientErrorException e) {
    log.error("image fetch failed", e);
    throw e;
}</byte[]>
// HttpURLConnection 예시
HttpURLConnection conn = (HttpURLConnection) new URL(imageUrl).openConnection();
int code = conn.getResponseCode();
if (code >= 400) {
    throw new RuntimeException("image fetch error: " + code);
}
// WebClient 예시
webClient.get()
    .uri(imageUrl)
    .retrieve()
    .bodyToMono(byte[].class)
    .block();
핵심 해석
이 경우 클라이언트 브라우저가 외부 이미지 서버를 다시 직접 호출하는 구조가 아니라, WAS가 먼저 외부 이미지를 요청했고 그 응답을 WAS가 동일한 소켓으로 받았기 때문에 WAS 로그에 예외가 찍힐 수 있다.

9. 최종 정리

현재까지 확인한 구조를 종합하면, 문제는 단순히 브라우저가 잘못된 이미지 URL을 요청했다는 수준에서 끝나지 않는다. 브라우저는 HTTP 이미지 URL을 발견하고 HTTPS 리다이렉트를 경험하지만, 내부에서는 Web ALB가 특정 경로를 Cloudgateway Target Group으로 분기한다. 이후 Cloudgateway와 NAT를 거쳐 외부 이미지 서버를 호출하고, 외부 서버가 404를 반환하면 그 응답은 새로운 인바운드가 아니라 기존 아웃바운드 세션의 응답으로 WAS까지 돌아온다. 그리고 WAS 또는 서버사이드 HTTP 클라이언트 코드가 그 404를 예외로 처리하면서 /runtime/exception 로그가 적재될 수 있다.

즉 이번 이슈의 핵심은 리다이렉트 자체보다도, ALB 분기 규칙, Cloudgateway를 통한 외부 호출, NAT의 세션 복원, 그리고 WAS의 404 처리 방식이 연결된 결과라고 보는 것이 가장 자연스럽다.