요약
존재하지 않는 public 경로가 HTTP 404 대신 SPA shell과 함께 HTTP 200을 반환합니다.
SEO/crawler/HTTP semantic 관점에서 잘못된 동작으로 보입니다.
재현
예시:
curl -i https://example.com/this-route-should-not-exist-audit
패치 전 결과:
응답 body는 SPA shell입니다.
Googlebot UA로 요청해도 동일하게 200이 반환되었습니다.
원인
web catch-all route가 등록되지 않은 경로까지 모두 SPA shell로 처리하고 있었습니다.
SEO middleware는 미등록 template route를 정상적으로 skip했지만, 이후 catch-all route로 fallback되면서 결국 200 응답이 반환되었습니다.
기대 동작
- 정상 SPA/template route -> 200
- 정상 SEO/static route -> 200
- 존재하지 않는 public route -> 404
- API route 동작은 기존 유지
이는 SPA 폴백을 완전히 비활성화하자는 것이 아니라, 폴백을 알려진 공용/템플릿 경로로 제한하자는 것입니다.
로컬 해결 방식
로컬에서는:
- 요청 경로가 실제 template route에 등록되어 있는지 먼저 확인
- 미등록 public 경로는
abort(404) 처리
방식으로 해결했습니다.
기존 정상 SPA 경로(/boards, /login 등)는 그대로 유지됩니다.
영향
- crawler가 존재하지 않는 페이지를 정상 페이지로 인식할 수 있음
- SEO parity가 깨질 수 있음
- monitoring/client 측에서 HTTP semantic이 왜곡됨
- static/SEO rendering contract를 추론하기 어려워짐
관련 운영 점검 및 runtime contract 관찰은 아래 글에도 정리해 두었습니다.
https://hub.glitter.kr/board/free/54
최근 실제 운영 환경에서 SEO/static renderer/API fallback contract가 서로 어떻게 어긋나는지 점검하던 흐름과 연결된 내용입니다.
요약
존재하지 않는 public 경로가 HTTP 404 대신 SPA shell과 함께 HTTP 200을 반환합니다.
SEO/crawler/HTTP semantic 관점에서 잘못된 동작으로 보입니다.
재현
예시:
패치 전 결과:
응답 body는 SPA shell입니다.
Googlebot UA로 요청해도 동일하게 200이 반환되었습니다.
원인
web catch-all route가 등록되지 않은 경로까지 모두 SPA shell로 처리하고 있었습니다.
SEO middleware는 미등록 template route를 정상적으로 skip했지만, 이후 catch-all route로 fallback되면서 결국 200 응답이 반환되었습니다.
기대 동작
이는 SPA 폴백을 완전히 비활성화하자는 것이 아니라, 폴백을 알려진 공용/템플릿 경로로 제한하자는 것입니다.
로컬 해결 방식
로컬에서는:
abort(404)처리방식으로 해결했습니다.
기존 정상 SPA 경로(
/boards,/login등)는 그대로 유지됩니다.영향
관련 운영 점검 및 runtime contract 관찰은 아래 글에도 정리해 두었습니다.
https://hub.glitter.kr/board/free/54
최근 실제 운영 환경에서 SEO/static renderer/API fallback contract가 서로 어떻게 어긋나는지 점검하던 흐름과 연결된 내용입니다.