Record/Trubble Shooting

[Trouble Shooting] 지도 포함 리포트 이미지 삽입 문제 해결

범데이 2026. 2. 18. 01:26

최근에 참여했던 프로젝트에서 출장 여비정산 리포트를 개발 과업 중에

“주행거리 증빙 화면(지도 포함)”을 이미지로 캡쳐해 ClipReport에 삽입해야 하는 과정이 있었다.

 

요구사항은 단순해 보였다.

  • 지도 화면이 반드시 포함된 상태로 캡쳐되어야 하고
  • 매번 다른 주행 경로를 동적으로 캡쳐해야 하며
  • 최종 결과는 리포트 안에서 이미지로 출력되어야 했다

하지만 실제 구현은 예상보다 훨씬 복잡했다.

 

이번 이슈는 아래와 같은 환경에서 발생했다.

  • Report: ClipReport
  • Frontend: React
  • Backend: Spring (Java)
  • Screenshot: Playwright (Headless Chromium)
  • Map SDK: Kakao Map SDK

그리고 문제는 단순히 “캡쳐가 안 된다” 수준이 아니었다.

 

이슈는 크게 세 가지 층으로 나뉘었다.

  1. 브라우저 렌더링 방식의 한계
  2. 서버 OS ↔ Playwright(Chromium) ↔ Java 패키지 호환
  3. 지도 SDK 도메인(URL) 매핑 문제

그리고 이 복잡한 문제들을 하나로 관통한 키워드는 로깅(Logging) 이었다.

 


 

1. 문제 배경: “지도 포함 주행거리 증빙 캡쳐” 요구사항

처음 목표는 아래처럼 정리할 수 있었다.

  • 특정 URL(증빙 페이지)을 로드한다
  • 페이지가 렌더링 완료되면 스크린샷을 찍는다
  • 생성된 이미지 파일을 ClipReport에서 출력한다

말만 보면 쉬운데, “지도(카카오맵/타일)”이 끼어들면서 난이도가 급상승했다.

 

 

 

2. 1차 시도: 프론트(html2canvas) 캡쳐 — 구조적 한계로 실패

처음에는 React 화면에서 html2canvas 기반으로 캡쳐해서 증빙 이미지를 만들려고 했다.

2.1 시도한 방식

  • html2canvas(contentRef.current) 로 화면을 캡쳐
  • 캡쳐된 이미지를 다운로드 또는 서버 업로드
  • 리포트에서 해당 이미지 출력

2.2 문제: “보이는 그대로 캡쳐”가 아니다

html2canvas와 같은 라이브러리는
브라우저 화면을 실제로 그대로 캡쳐하는 방식이 아니다.

 

canvas 위에 현재 렌더링된 HTML / CSS 구조를 분석해서
비슷하게 보이도록 다시 그리는 방식”이다.

 

이 구조적인 특성 때문에 다음과 같은 문제가 발생했다.

  • 일부 UI 요소 (특히 input, form 요소)가 틀어짐
  • 스타일이 완벽하게 재현되지 않음
  • 외부 스크립트 기반 요소(지도 SDK 등)가 정상적으로 그려지지 않음
  • 지도 영역 및 타일 이미지가 제대로 표현되지 않음

실제로 여러 캡쳐 라이브러리를 테스트해봤지만
공통적으로 동일한 문제가 발생했다.

 

 

결론적으로,  “프론트에서 보이는 화면을 그대로 캡쳐한다”는 접근 자체가
기술적으로 완전한 재현을 보장하지 못한다.

 

특히 지도와 같은 외부 렌더링 요소가 포함되면
정확한 결과를 얻기 어렵다.

 

결론: “프론트에서 보이는 화면을 캡쳐” 방식은

지도/외부 리소스가 포함되면 구조적으로 실패할 가능성이 높다.

 

따라서 방향을 변경했다.

 

 

3. 방향 전환: 서버에서 페이지를 직접 요청/렌더링해서 캡쳐하자

프론트 캡쳐 방식의 한계를 확인했기 때문에, 서버가 Headless Chromium을 실행해서 캡쳐하도록 구조를 전환했다.

즉,

  • 서버가 Playwright로 브라우저를 띄우고
  • 해당 URL에 접속해 렌더링한 뒤
  • 렌더링 결과를 스크린샷으로 저장한다

이 방식은 “보이는 그대로”를 캡쳐하기에 적합하다.

 

 

 

4. 2차 장애: 서버 OS ↔ Playwright 버전/Chromium 호환 문제

서버에서 Playwright를 올리고 실행하는 순간, 다음과 같은 문제가 발생했다.

  • Chromium이 정상 구동되지 않거나
  • OS 지원 경고가 뜨거나
  • fallback build 다운로드로 인해 불안정하게 동작했다

여기서 포인트는 “코드가 잘못됐다”가 아니라:

서버 OS 환경과 Playwright/Chromium 빌드가 맞지 않으면

브라우저 자체가 실행되지 않는다.

 

4.1 해결: Playwright 버전 다운그레이드

결국 이 문제는 Playwright 버전을 낮추는 방향으로 해결했다.

  • 최신 버전은 서버 OS(또는 glibc 등)와 호환이 애매했고
  • 낮춘 버전에서는 Chromium이 정상 실행되었다

 

✅ 결과:

  • 페이지 접속 성공
  • 스크린샷 생성 성공

여기까지 오면 끝일 줄 알았지만, 진짜 문제는 다음 단계였다.

 

 

 

5. 3차 장애: “캡쳐는 되는데 지도 SDK가 안 뜬다”

Chromium이 뜨고 캡쳐도 된다.

그런데 결과 이미지에 지도만 안 나온다.

  • 페이지는 정상
  • 텍스트/레이아웃도 정상
  • 그런데 지도 영역만 비어 있음

이 시점부터는 코드 문제가 아니라 환경/네트워크/보안/SDK 정책 영역으로 넘어간다.

 

 

6. 이때부터 결정적으로 중요해진 것: 로깅(Logging)

여기서부터는 감으로 때려맞추면 시간이 10배 걸린다.

내가 했던 핵심은:

6.1 서버 네트워크 레벨 검증

  • 서버에서 curl 로 해당 URL 접근 가능한지 확인
  • 지도 SDK 스크립트 주소 접근 가능한지 확인
  • 외부망 라우팅/DNS/방화벽 이슈 가능성 제거

6.2 Playwright 브라우저 로그 출력

브라우저 단에서만 보이는 에러가 있다.

따라서 로그를 찍었다.

  • console log
  • requestfailed
  • response status
  • network trace

이걸 통해 결론적으로 파악한 핵심은:

지도 SDK는 “등록된 URL(도메인)”에서만 정상 동작한다.

 

 

 

7. 근본 원인: 지도 SDK는 허용된 URL/도메인이 일치해야 로드된다

내 서버 캡쳐 환경에서는 다음과 같은 차이가 있었다.

  • 원래 SDK 호출 기준 URL이 내부망 기반(172.x.x.x)으로 잡혀 있었고
  • 로컬/외부에서 접근할 때는 외부망 IP로 호출되었다

지도 SDK는 도메인 정책이 강해서:

  • 등록된 URL과 다르면
  • SDK가 로드되지 않거나 일부 기능이 차단된다

 

8. 해결: 지도 SDK가 인식하는 URL을 “등록된 주소로 통일” (URL 매핑)

따라서 해결책은 단순했다.

  • 서버에서 지도 SDK를 호출할 때도
  • SDK에 등록된 URL과 동일한 형태로 인식되도록
  • 내부망 IP → 외부망 IP 기반 호출로 변경
  • 로컬 호출 환경과 동일한 IP/도메인 기준으로 통일

✅ 결과:

  • 서버 Playwright 환경에서도 지도 SDK 정상 로드
  • 지도까지 포함된 증빙 화면 캡쳐 성공

 

9. 최종 결론: 이번 이슈의 핵심 정리

이번 문제는 “기술”이 여러 층으로 겹쳐져 있었다.

(1) 프론트 캡쳐 방식은 구조적 한계가 존재한다

html2canvas와 같은 방식은 실제 캡쳐가 아니라 재렌더링이기 때문에
지도/외부 렌더링 요소 포함 시 정확한 결과를 보장하기 어렵다

 

(2) 서버 캡쳐는 OS 호환성이 승패를 가른다

Playwright 최신이 항상 정답이 아니다

서버 OS / glibc / 패키지 호환성이 맞아야 Chromium이 뜬다

 

(3) 지도 SDK는 “URL 정책” 때문에 예상치 못하게 실패한다

SDK는 허용 도메인 기반으로 동작한다
서버에서 띄우면 host/origin이 달라져서 SDK가 막힐 수 있다
해결은 “등록된 URL로 통일(매핑)”이다

 

(4) 결정타는 로깅이었다

curl로 네트워크 확인
Playwright에서 console/network 로깅
이게 없었으면 “지도 안 뜨는 이유”는 끝까지 감으로만 맞췄을 것이다

728x90
반응형