1. 문제 상황

- 현상: 지하철 혼잡도 조회 시 백엔드 터미널에 MISSING_AUTHENTICATION_TOKEN (code: gw, id: 403) 에러 발생.
- 의미: SK Open API 서버가 요청을 받았으나, 헤더에 필수 인증 정보인 appKey가 누락되었음을 의미함.
- 특이사항: .env 파일에 분명히 SK_API_KEY가 존재함에도 불구하고 발생.
2. 원인 분석
조사 결과, 단순히 키가 없는 것이 아니라 환경 변수를 로드하는 시점과 경로에 복합적인 문제가 있었습니다.
- 환경 변수 로드 경로 오류: dotenv.config()는 기본적으로 프로세스 실행 위치(CWD)에서 .env를 찾습니다. 루트 디렉토리에서 서버를 실행할 경우 backend/.env를 찾지 못해 process.env.SK_API_KEY가 undefined가 됨.
- 모듈 로드 순서(Race Condition): index.ts에서 API 관련 모듈(skApi)을 먼저 임포트한 뒤에 dotenv.config()를 호출함. 이로 인해 axios 인스턴스가 생성되는 시점에는 아직 환경 변수가 메모리에 올라오지 않아 빈 값이 할당됨.
- 에러 가시성 부족: 기존 코드에서 API 에러의 상세 응답 내용을 로깅하지 않아, 어떤 값이 누락되었는지 즉각적인 파악이 어려웠음.
3. 해결 방법
① 환경 변수 로드 방식 개선 (backend/src/config/api.ts)
실행 위치에 상관없이 항상 .env를 읽어올 수 있도록 절대 경로를 사용하고, appKey 헤더 설정을 보장합니다.
TypeScript
import axios from 'axios';
import dotenv from 'dotenv';
import path from 'path';
// 현재 파일 위치 기준, backend 폴더의 .env를 명시적으로 로드
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
const SK_API_KEY = process.env.SK_API_KEY;
export const skApi = axios.create({
baseURL: 'https://apis.openapi.sk.com/',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'appKey': SK_API_KEY || '', // 로드된 키를 헤더에 주입
},
});
② 서버 엔트리 포인트 수정 (backend/src/index.ts)
다른 모든 모듈(특히 API 관련 모듈)이 임포트되기 전에 최상단에서 환경 변수를 먼저 로드하도록 수정했습니다.
TypeScript
// 반드시 다른 import들보다 위에 위치해야 함
import dotenv from 'dotenv';
import path from 'path';
dotenv.config({ path: path.resolve(__dirname, '../.env') });
import express from 'express';
// ... 이후 나머지 routes 및 middleware 임포트
③ 에러 핸들링 강화 (backend/src/services/CongestionService.ts)
외부 API 오류 발생 시 상세 메시지를 터미널에 출력하여 추후 대응이 쉽도록 개선했습니다.
TypeScript
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message;
console.error('Error fetching congestion data from SK API:', errorMessage);
throw new Error(`SK API 오류: ${errorMessage}`);
}
4. 결과 확인 (Verification)
- 서버 재시작 후 로그에 Critical Error: SK_API_KEY is not defined가 뜨지 않는지 확인.
- 혼잡도 API 호출 시 200 OK 응답과 함께 정상적인 JSON 데이터 수신 확인.
💡 요약 및 교훈
- 환경 변수는 항상 최우선으로: API 설정 파일이나 서버 시작 파일 최상단에서 가장 먼저 로드되어야 한다.
- 경로는 명시적으로: dotenv 사용 시 실행 환경(루트 vs 서브디렉토리)에 따라 파일 경로가 꼬일 수 있으므로 path.resolve를 쓰는 것이 안전하다.
'트러블슈팅' 카테고리의 다른 글
| [트러블 슈팅] 6000명이 동시에 쿠폰 발급을 요청한다면? (0) | 2026.04.28 |
|---|---|
| [트러블 슈팅] API 라우팅 경로 불일치로 인한 Cannot GET 에러 해결 (0) | 2026.04.08 |
| [JPA] JPA 테이블 생성 (0) | 2025.12.05 |
| 트러블 슈팅/ 데이터 무결성 (0) | 2025.11.18 |
| 트러블 슈팅/ 퍼블릭 IP로 서버 접속하기 (0) | 2025.11.13 |