2026. 3. 29. 14:52ㆍProject
개발 과정에서 가장 당혹스러운 순간은 로컬 환경에서는 완벽하게 작동하던 기능이 배포 후 서버에서 침묵할 때다..나도 알고싶지 않았다.. 특히 KAMIS(농수산유통정보)와 공공데이터 포털의 영양정보 API를 연동하며 겪은 '외부 API와의 혈투'는 네트워크 보안과 데이터 규격의 중요성을 뼈저리게 느끼게 해주었다. 그 트러블슈팅 기록을 정리한다.
1. SSL 핸드셰이크 실패: 보안 프로토콜의 세대 차이
가장 먼저 맞닥뜨린 난관은 SSL(Secure Sockets Layer) 인증 오류였다. 최신 우분투(Ubuntu)(이제부터 내 인스턴스는 지우고 팀원 서버에서 같이 스터디하며 배포했다.) 서버는 강화된 보안 가이드라인에 따라 최신 TLS 프로토콜을 요구하지만, 일부 오래된 공공기관 API 서버는 여전히 낮은 버전의 보안 규격을 사용하고 있었다. 우리 프로젝트에는 실시간 API가 서로 연동되어있었는데 그중 시세를 나타내는 KAMIS API가 오래되어 규격이 맞지 않아 프론트에 띄워지지 않았다.
- 현상: requests.exceptions.SSLError 발생. 서버 간의 보안 연결(Handshake) 단계에서 규격 불일치로 연결이 차단됨.
- 해결: verify=False와 경고 제어
- 임시방편으로 Python requests 라이브러리의 인증서 검증 기능을 비활성화하여 연결을 강제했다.
import requests
import urllib3
# 인증서 검증 미실시에 따른 경고 메시지 억제
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# verify=False 설정을 통해 보안 검증 우회
response = requests.get(url, verify=False)
참고: verify=False는 데이터 통신 보안을 취약하게 만들 수 있으므로, 실제 운영 환경에서는 서버의 OpenSSL 설정을 조정하거나 해당 기관에 보안 업데이트를 요청하는 것이 근본적인 해결책이다.
2. 500 Internal Error: 인코딩(Key)의 함정
공공데이터 포털 API 사용 시 가장 빈번하게 발생하는 오류는 500 Internal Server Error다. 가이드에 적힌 대로 인증키를 입력했음에도 서버가 응답하지 않는 이유는 대부분 키 인코딩 방식에 있었다.
중복 인코딩 문제
공공데이터 포털은 '인코딩된 키'와 '디코딩된 키'를 동시에 제공한다. Python의 requests 라이브러리는 URL 파라미터를 전달할 때 내부적으로 자동 인코딩을 수행한다. 이때 이미 인코딩된 키를 인자로 넘기면 % 기호가 %25로 변하는 중복 인코딩이 발생하여 인증에 실패하게 된다.
| 문제 유형 | 주요 원인 | 대응 방안 |
| Invalid Service Key | 인증키 오타 또는 인코딩 중복 | Decoded Key 사용 생활화 |
| 500 Error | API 서버 내부 마비 또는 필수 파라미터 누락 | 예외 처리 및 재시도(Retry) 로직 구현 |
| Limited Request | 일일 호출 트래픽 초과 | API 활용 신청 페이지에서 트래픽 증설 신청 |
3. DB Fallback: 외부의 불안정성에 대비하는 안전장치
외부 API는 본질적으로 우리가 통제할 수 없는 영역이다. API 서버가 점검 중이거나 응답 속도가 비정상적으로 느려질 경우, 우리 서비스 전체의 가용성이 떨어지는 치명적인 문제가 발생한다. 이를 방지하기 위해 DB Fallback 전략을 도입했다.
안전장치 작동 원리
- Primary: 실시간 외부 API 호출을 시도한다.
- Exception: 타임아웃이나 API 에러가 발생할 경우 이를 즉시 캐치한다.
- Fallback: 우리 DB에 미리 저장(Caching)해둔 과거 데이터나 기본 규격 정보를 반환한다.
교훈: 외부 데이터는 언제든 끊길 수 있다는 전제하에 설계해야 한다. 사용자에게 에러 메시지를 보여주는 것보다, 조금 오래된 데이터일지라도 안정적인 UI를 제공하는 것이 사용자 경험(UX) 측면에서 훨씬 유리하다.
외부 API 연동은 단순한 데이터 수신을 넘어, 서로 다른 환경을 가진 두 시스템 사이의 접점을 조율하는 과정이었다. SSL 버전 차이부터 인코딩 이슈, 그리고 서버 불안정성까지 해결하며 시스템의 견고함을 한 단계 높일 수 있었다. 이제 슬슬 배포 마무리 하고 싶은데 왜 끝이 안나지..? 처음엔 목표가 일주일안에 끝내는 것이었는데, 아무래도 각자 다른 프로젝트를 진행하면서 하루에 1시간 ~1시간 30분씩 진행을 하다보니 진도가 조금 느려졌다. 곧 끝나니 조금만 더 힘내자!
'Project' 카테고리의 다른 글
| [DB_Insight Project] 나만의 AI DB 비서, 그 첫 번째 기록 (feat. RAG & 하이브리드 검색) (0) | 2026.04.02 |
|---|---|
| [Meat-A-Eye 배포] 마지막 트러블 슈팅 (0) | 2026.03.30 |
| [Meat-A-Eye 배포] GPU 다이어트 (0) | 2026.03.28 |
| [Meat-A-Eye 배포] Docker를 활용한 배포 및 AWS 리전 트러블 슈팅 (0) | 2026.03.25 |
| [Meat-A-Eye 프로젝트] Data-Centric AI 기반 육류 부위 판별 핵심 로직 (1) | 2026.02.14 |