1. 문제 상황
MenuMate 프로젝트에서 레시피 검색 기능을 구현하던 중, 다음과 같은 문제가 발생했습니다.
- 검색어 입력 후 제출 시에는 정상적으로 결과가 나옴
- 뒤로가기 / 새로고침 시 간헐적으로 500 에러 발생
- 검색 중 오류 발생시 출력되는 '레시피 검색 기능을 구현하던 중, 다음과 같은 문제가 발생'가 나옴

항상 성공하는 것도 아니고 항상 실패하는 것도 아닌 간헐적으로 검색 요청이 실패하는 문제 상황을 이해할 수 없었습니다.
2. 초기 의심 포인트
처음에는 다음과 같은 가능성들을 의심했습니다.
- API route(/api/search) 로직 문제
- searchRecipes()(검색 유스케이스 진입점) 내부 로직 문제
- JSON 파싱 에러
- 네트워크 오류
이중에서 특정 상황에서만 발생하는 조건부 원인을 찾아보고자 했습니다.
3. 문제 원인 파악(디버깅 과정)
3-1. 서버 로그 확인
디버깅 로그를 추가한 뒤, 터미널에서 다음 에러를 확인했습니다.
SyntaxError: Unexpected token '<'
찾아본 결과, JSON 파싱 중 HTML이 들어온 경우에 발생하는 전형적인 에러였습니다. 하지만 식약처 API의 반환값이 특정 상황에서만 달라진다는 것은 조금 이상했습니다.
3-2. 응답 원문 확인
하지만 아직 확실하다고 판단되지 않아 response.text()로 원문을 확인해보니 다음과 같은 응답이 나왔습니다.
<script type="text/javascript">
alert('현재 접속 중인 인증키입니다. 잠시 후에 다시 시도하십시오.');
history.back();
</script>
3-3. 핵심 원인 발견
해당 응답으로 핵심 원인이 같은 API 키로 동시에 여러 요청이 들어와서 차단된다는 것을 알 수 있었습니다.
실제로 에러 재현 테스트때 빠르게 새로 고침을 여러번 하거나 뒤로가기 및 앞으로가기를 빠르게 연속적으로 할 경우 해당 에러가 터지는 것을 볼 수 있었습니다.
핵심 원인을 요약해보자면 다음과 같습니다.
- 식약처 API는 동시 요청 제한 정책이 있음
- 동일 키로 여러 요청이 동시에 들어오면 JSON 대신 HTML + alert 응답을 반환
4. 문제의 본질
이번 500에러 문제의 핵심은 두 가지 원인이 결합된 것이었습니다.
- 클라이언트에서 중복 요청 발생
- 같은 검색어로 짧은 시간 안에 여러 fetch 발생 - 외부 API의 동시 요청 제한
- 동일 API키 동시 요청 시 차단
즉, JSON 파싱, Next.js API 등이 원인이아니라 중복 요청과 외부 API 제한 정책이 원인이었습니다.
5. 해결 방법 (debounce 적용)
이번 문제는 동일 검색어로 요청이 짧은 시간에 여러 번 오기에 발생했다고 볼 수 있습니다.
따라서 가장 근본적이 해결 방안은 '요청 자체를 줄이는 것' 혹은 '요청 사이의 시간 차를 두는 것'이라고 생각했습니다.
그렇기 때문에 프론트 차원에서 debounce를 적용해 검색 요청을 바로 보내지 않고 일정 시간 대기 후 실행하도록 수정했습니다.
const SEARCH_DEBOUNCE_MS = 300;
useEffect(() => {
if (!q) return;
const timerId = setTimeout(() => {
fetchSearchResults(q);
}, SEARCH_DEBOUNCE_MS);
return () => clearTimeout(timerId);
}, [q]);
6. 수정 결과
debounce 적용 이후 아래와 같은 변경점이 생겼습니다.
- HTML 응답 발생 빈도 감소
- 뒤로가기/새로고침 시 500에러 사라짐
- 검색 UX 안정화
7. 이번 경험을 통해 배운 점
7-1. 외부 API가 항상 “정상 JSON”을 주는 것은 아닐 수 있다
- HTML, script, 에러 페이지 등 다양한 형태 가능
- 반드시 방어 코드 필요
7-2. 500에러의 원인은 서버 코드가 아닐 수도 있다
- 클라이언트 요청 패턴이 원일일 수 있음
7-3. '간헐적 에러'는 타이밍 문제를 의심해야 한다
- 레이스 컨디션(Race Condition, 경쟁 상태): 두 개 이상의 스레드나 프로세스가 공유 자원에 동시에 접근하여 데이터를 조작할 때, 실행 순서에 따라 결과가 달라지는 비결정적 상황
- 중복 요청
- 외부 API 제한
무엇보다, 이번 경험을 통해 문제의 원인을 코드에서만 찾지말고, 요청 흐름 전체에서 봐야 한다는 것을 깨달았습니다.
'개인 프로젝트 MenuMate' 카테고리의 다른 글
| MenuMate 검색 로직 리팩토링 작업 (상태 관리 -> 캐시 관리) (0) | 2026.04.15 |
|---|---|
| TypeScript가 css import를 타입으로 인식하지 못하는 문제 해결 과정 (0) | 2026.04.14 |
| Next.js next/image 외부 이미지 오류 문제 해결 경험 정리 (0) | 2026.04.02 |
| App Router 구조 오해로 인한 build 오류 문제 해결 과정 (0) | 2026.03.31 |
| MenuMate 외부 API Raw타입 정규화 과정 정리, 레시피 페이지 조회 흐름 요약 (0) | 2026.03.30 |