Files
document-haness/docs/TechLog/tech-log-studio/one-route-many-hand-kept-lists/case/case-a-route-the-web-server-never-heard-of.md
T
DongHyeonkaandClaude Opus 5 193da20d09 docs(TechLog): Reference 15편의 규칙 표기를 게시된 기록에 맞추고 주제 6 을 다시 쓴다
게시된 Reference 15편이 전부 규칙을 `### N. 제목` 으로 쓰고 적용 조건·예외·예시를 항목으로
쓴다. 내 15편은 규칙을 `**굵게**` 로, 나머지 셋을 문단으로 쓰고 있었다 — Studio 의
rules[]·applyWhen[]·exceptions[]·examples[] 는 배열이라 문단으로 두면 항목이 하나로 접힌다.

  규칙 68개를 `### N. 제목` 으로 바꿨다 (편당 3~7개, 게시된 것은 4~10개)
  적용 조건·예외·예시를 항목으로 갈랐다. 한 항목뿐이던 아홉 편은 조건을 나눠 적었다

주제 6 은 본문을 다시 썼다 — location = 이 정확히 일치하는 경로만 잡아 27개가 얼어붙은
구조, 여덟 곳이 우는 시점을 셋으로 가른 표, digest 를 다시 계산할 때 옛 값을 먼저
재현하는 이유.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 19:01:44 +09:00

5.8 KiB

kind, slug, title, topic, topicName, project, status, lastVerifiedOn, sourceRevision, source
kind slug title topic topicName project status lastVerifiedOn sourceRevision source
CASE a-route-the-web-server-never-heard-of nginx 가 모르는 라우트는 새로고침에서 404 다 one-route-many-hand-kept-lists 라우트 하나가 울리는 손 목록 TechLog 게시 전 2026-09-04 tech-log@2026-09-02
final/document.md#§8.2
final/document.md#§12.6

nginx 가 모르는 라우트는 새로고침에서 404 다

/studio/releases 가 평문 404 를 돌려줬다. 라우트는 있고 청크도 빌드됐고 SPA 내부 이동으로는 화면에 닿는데, 하드 로드와 새로고침은 거기까지 가지 못한다. nginx 설정이 손으로 유지하는 배열에서 나오고 있었다.

관계

  • 라우트에 딸린 목록은 라우트 계약에서 유도하고, 유도할 수 없는 것은 대조 검사를 둔다 이 사건에서 굳힌 기준이다.
  • catch-all 라우트는 nginx 패턴으로 번역하지 않는다 같은 유도 규칙의 일부로 정했다.
  • 라우트 하나가 건드리는 여덟 곳과, 그것들이 우는 시점 같은 부류가 다른 목록에서 어떻게 우는지가 그 기록에 있다.

문제

SPA 안에서 이동하면 화면이 열린다. 주소창에 그 주소를 직접 넣거나 새로고침하면 nginx 가 평문 404 를 준다.

웹 서버가 그 경로의 존재를 들은 적이 없기 때문이다. 서빙 계약이 어느 경로를 SPA 로 넘길지 정하는데, 그 목록에 없는 경로는 넘어가지 않는다.

결론

서빙 계약의 절반은 라우트 레지스트리에서 유도하고 있었고 나머지 절반은 손으로 유지하는 배열이었다.

서빙 계약의 공개 절반은 라우트 레지스트리에서 패턴을 유도한다. Studio 절반은 손으로 유지하는 배열이었고, 손으로 유지하는 배열이 실패하는 방식 그대로 실패했다^/studio/assets$ 위의 주석이 바로 그 버그를 한 번 고친 기록이고, 라우트를 더하니 즉시 반복됐다.

공개 절반도 유도라고 하기 어려웠다. 번들된 픽스처에 우연히 들어 있던 공개 경로를 전부 열거하고, 생성된 nginx 가 정확히 그것들을 location = 블록으로 게시했다. 빌드 이후에 게시된 기록은 SPA 에 묻기도 전에 엣지에서 404 였다. 경로 27개가 얼어 있었고 28번째는 무엇이든 닿을 수 없었다.

지금은 라우트 계약에서 등록된 Public 라우트마다 정규식 하나를 만든다. 파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않으므로 /cases/a/b 는 404 로 남는다.

검증 환경

tech-log-frontend : ab8c6c1 · 6784eb1 엣지 : nginx (서빙 계약에서 생성) 확인 방식 : 생성된 서빙 패턴이 라우트 계약과 같은지 보는 테스트

재현 조건

  1. 라우트를 하나 더하고 서빙 계약 배열에는 넣지 않는다
  2. 빌드하고 배포한 뒤 그 주소를 주소창에 직접 넣는다 — 평문 404 가 온다
  3. SPA 안에서 링크로 이동한다 — 화면이 열린다

본문

내부 이동은 되고 하드 로드는 안 된다

SPA 안에서 이동할 때는 라우터가 화면을 그리므로 웹 서버가 개입하지 않는다. 주소를 직접 넣거나 새로고침하면 웹 서버가 그 경로를 먼저 받는다.

서빙 계약에 그 경로가 없으면 nginx 는 SPA 로 넘기지 않고 평문 404 를 준다. 그래서 「내부에서는 되는데 새로고침하면 안 된다」로 나타나고, 개발 중에는 대개 내부 이동으로만 화면에 닿으므로 배포 뒤에 드러난다.

손으로 유지하는 절반

서빙 계약의 절반은 라우트 레지스트리에서 유도하고 있었고 나머지 절반은 배열이었다.

서빙 계약의 공개 절반은 라우트 레지스트리에서 패턴을 유도한다. Studio 절반은 손으로 유지하는 배열이었고, 손으로 유지하는 배열이 실패하는 방식 그대로 실패했다^/studio/assets$ 위의 주석이 바로 그 버그를 한 번 고친 기록이고, 라우트를 더하니 즉시 반복됐다.

그 주석이 남아 있었다는 것이 이 건의 성격을 말한다. 같은 배열을 한 번 고치면서 왜 고쳤는지를 적어 두었는데, 다음 사람이 그 배열에 줄을 더할 때 그 주석을 읽지 않았다.

얼어붙은 27개

공개 절반도 유도라고 하기 어려웠다. 서빙 계약이 번들된 픽스처에 우연히 들어 있던 공개 경로를 전부 열거하고, 생성된 nginx 가 정확히 그것들을 location = 블록으로 게시했다.

location = 은 정확히 일치하는 경로만 잡는다. 그래서 빌드 시점에 픽스처에 있던 27개는 열리고, 빌드 이후에 게시된 기록은 SPA 에 묻기도 전에 엣지에서 404 였다 — 백엔드를 두는 이유 그 자체가 그 경계에서 막혔다.

라우트 계약에서 유도한다

지금은 라우트 계약에서 등록된 Public 라우트마다 정규식 하나를 만든다.

파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않는다. 그래서 /cases/a/b 는 404 로 남고, 그 주소가 잘못됐다는 것이 방문자에게도 감사에게도 드러난다.

같은 구조가 파일에도 걸렸다

robots.txt 도 404 였다. 파일은 이미지에 있었지만 nginx 설정이 서빙할 파일을 하나씩 명시하는 구조라 등록되지 않은 것은 SPA 폴백으로 떨어진다.

폴백은 index.html 을 준다. 사람에게는 화면이 뜨는 것처럼 보이지만 크롤러는 그 HTML 을 robots 규칙으로 읽을 수 없다.

확인하지 못한 것

경로 27개가 얼어 있던 상태의 생성 결과물은 남기지 않았다. 지금 생성되는 패턴이 라우트 계약과 같은지만 테스트가 본다.