← 전체 글로 돌아가기

Next.js

React 폼이 서버에서만 제출 안 될 때 디버깅

로컬에선 멀쩡한데 운영 서버에서만 폼 제출이 안 될 때의 체크리스트.

운영 서버에서만 로그인 폼이나 댓글 폼 제출이 안 되는 경험을 했다. 로컬에선 당연히 잘 된다. 이런 경우 원인을 찾기가 정말 어렵다.

일반적으로 "서버에서만" 문제는 환경 차이에서 비롯된다. 네트워크, CORS, 타임아웃, 권한 등이 로컬과 다를 수 있다.

먼저 할 것: 브라우저 개발자 도구

서버에서 직접 폼을 제출해보고 Network 탭에서 요청과 응답을 본다:

  • 상태 코드: 200? 400? 500? 308 (리다이렉트)?
  • 응답 헤더: Access-Control-Allow-Origin이 있나?
  • 응답 본문: 에러 메시지?

4xx 에러면 입력 데이터나 인증 문제. 5xx면 서버 로직 버그. 타임아웃이면 느린 API나 무한 루프.

CORS 문제인지 확인

// 개발자 도구 콘솔
console.error  // CORS 에러 메시지

// Network 탭에서 Preflight 요청 (OPTIONS) 확인

POST나 PUT 요청이면 브라우저가 먼저 OPTIONS 요청을 보낸다. 이게 실패하면 실제 요청도 안 간다.

CORS 에러가 보이면:

  • 백엔드의 Access-Control-Allow-Origin 설정 재확인
  • Express/Next.js라면 미들웨어 체크: cors() 패키지나 헤더 설정

로컬 vs 운영 환경 차이 비교

# 로컬 (작동함)
curl -X POST http://localhost:3000/api/submit \
  -H "Content-Type: application/json" \
  -d '{"name":"test"}'

# 운영 (안 됨)
curl -X POST https://yoursite.com/api/submit \
  -H "Content-Type: application/json" \
  -d '{"name":"test"}'

두 curl 결과가 다르면 뭔가 다르다는 증거다.

폼 데이터 인코딩 확인

// 로컬에서 작동하는 코드
fetch('/api/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(data)
})

Runtime에 보낸 데이터가 뭔지, 헤더가 뭔지 로깅해본다. 서버에서 예상한 형식과 일치하는지 확인한다.

운영에만 문제면:

  • API 게이트웨이(Nginx, Traefik)가 헤더를 제거하거나 변조했을 수도
  • 바디 크기 제한에 걸렸을 수도

백엔드 로그 확인

# 운영 서버 로그
docker logs app-service
kubectl logs deployment/app

# 또는 애플리케이션 로그 파일
cat /var/log/app.log | grep -A 10 -B 10 'submit'

폼 요청이 서버에 도달했는지, 어디서 실패했는지 본다.

  • 라우트 매칭 실패?
  • 미들웨어에서 차단됨? (인증, CSRF 토큰 검증 등)
  • DB 연결 실패?

CSRF 토큰이 있다면 확인

# CSRF 토큰 검증 실패
Fetch error: 403 Forbidden (CSRF token mismatch)

CSRF 보호가 켜져있다면:

  • 토큰이 폼에 포함됐는가?
  • 서버의 토큰 검증 로직이 환경별로 다른가?
  • 쿠키 설정 (SameSite, Secure) 때문에 토큰이 안 전달되나?

타임아웃 확인

네트워크 탭에서 요청이 끝나지 않고 계속 대기 중이라면 타임아웃 문제다:

# 서버 응답 시간 확인
curl -w "Total time: %{time_total}s\n" -X POST https://yoursite.com/api/submit

30초 이상이라면:

  • API가 느린 외부 서비스를 호출 중?
  • 데이터베이스 쿼리가 느림?
  • 운영 서버의 리소스가 부족? (CPU, 메모리)

정리하기 전에 기록해두기

  • Network 탭 스크린샷 (요청/응답 헤더와 바디)
  • 백엔드 로그의 해당 시간대 내용
  • 로컬에서의 정상 동작 curl 명령과 결과
  • 운영에서의 실패 curl 명령과 결과

이 네 가지 증거로 원인을 3개 후보로 줄일 수 있다.