기존 UI에서 로그인 버튼을 사이드 바로 이동시키고
기존 로그인 자리를 김치 프리미엄을 보여주고 싶어
바이낸스 측 api를 쓰기 시작했다.
문제는 배포 이후 502 에러가 뜬 것이다.
로컬 환경에서는 문제가 없었고
우선 vercel 배포 페이지에 넘어가서
api 호출을 보니깐 kimchi 프리미엄 파트에서 에러 비율이 100%
일어나고 있었다.
에러 로그를 보니깐 바이낸스 측에서 451를 반환하고 있었고
이유는 다음과 같았다.
로그 메시지: [kimchi] Binance error 451
바이낸스가 요청을 보낸 IP 주소를 법적/지역적 이유로 차단했기 때문에 발생한 것이다.
원래 코드는 Upbit, Binance, FX 호출을 Promise.all로 동시에 비동기 요청하는 방식이었다.
Binance API를 호출할 때, Next.js API Route가 Vercel의 서울(icn1) 리전에서 실행되면서 해당 리전의 IP 주소가 바이낸스의 지역 차단 목록에 포함되었을 가능성이 매우 높다고 생각한다.
원래 코드가 502 Bad Gateway로 연결될 수 있었던 치명적인 구조적 취약점은 외부 API 호출에 대한 명시적인 타임아웃 처리가 없었다는 점이었다.
기존 코드는 fetch 호출에 타임아웃 로직이 없었기 때문에,
Binance가 451 응답을 반환하지 않고 단순히 연결이 끊기거나 응답이 지연되는 경우, Vercel Lambda 함수의 기본 타임아웃에 도달할 때까지 함수가 기다리다가
함수가 Vercel의 타임아웃 제한을 초과하여 강제 종료되면, Vercel은 클라이언트에게 502 Bad Gateway를 반환하고 있던 것이다.
또한,
Binance 서버 호스트를 api.binance.com으로 단일 고정했기 때문에, 이 하나의 호스트가 차단되면 무조건 실패했던 점..
타임아웃 withTimeout(url, 3500) 함수를 도입하여 모든 외부 API 호출(Upbit, Binance, FX)에 3.5초의 제한 시간을 명시적으로 적용.
API 지연으로 인한 Vercel Lambda 전체 타임아웃(504) 방지.
Binance 폴백 fetchBinancePrice 함수 내에서 api.binance.com 외에 api1, api2, api3, data-api.binance.vision 등 다중 호스트를 순차적으로 시도하도록 변경.
단일 호스트 차단 (예: 451 에러) 시 다른 호스트를 시도하여 성공률 극대화.
서울(icn1) IP가 Binance에 의해 451로 차단되는 문제를 우회하기 위해 도쿄(hnd1)나 싱가폴(sin1) 리전을 우선적으로 사용하도록 설정.
원래 코드는 세 가지 호출을 Promise.all로 묶어 동시에 실행했지만, 교체 코드는 이 방식을 더 안정적으로 분리.
Binance는 별도 함수로 호출
이 방식은 Binance 호출이 실패하더라도 다른 데이터는 성공적으로 가져왔는지 확인하고, Binance 호출 내부에서 다중 폴백을 처리하게 함으로써 에러 핸들링의 명확성을 높였습니다.
결론적으로, 문제는 Vercel의 서울 IP가 바이낸스에 의해 차단(451)당한 것이었으며, 교체 코드는 이 문제를 리전 우선순위 변경으로 우회하고, 타임아웃 및 다중 호스트 폴백을 도입하여 전체 API의 구조를 변경하면서 해결을 했다.