Workers 정적 자산에서 트레일링 슬래시가 인덱싱을 흔드는 이유
Astro trailingSlash never와 wrangler html_handling drop-trailing-slash를 맞춘 뒤, /page와 /page/가 어떻게 갈라지는지 공식 문서와 실측으로 정리합니다.

서민혁닷컴을 Workers 정적 자산으로 올린 뒤 가장 먼저 신경 쓴 건 광고봇 차단이 아니었다. /posts/foo와 /posts/foo/가 서로 다른 문서로 잡히면 검색엔진이 캐노니컬을 헷갈린다. Cloudflare 문서도 같은 경고를 한다. 트레일링 슬래시 유무를 다른 URL로 취급하면 중복 콘텐츠·인덱싱 혼란이 난다는 이야기다.
사실: 네 가지 html_handling
Workers 정적 자산의 assets.html_handling은 요청 경로를 어디로 리다이렉트·리라이트할지 정한다. 공식 옵션은 네 가지다.
auto-trailing-slash(기본): 파일은 슬래시 없이, 폴더index.html은 슬래시 있게force-trailing-slash: 대부분/path/로 모음drop-trailing-slash: 대부분/path로 모음none: 내장 HTML 처리 끔.not_found_handling에 더 의존
이 사이트는 Astro trailingSlash: 'never'와 맞춰 wrangler.jsonc에 html_handling: "drop-trailing-slash"를 넣었다. 문서 표 기준으로 /file/ → 307 /file, /folder/ → 307 /folder로 떨어진다. /file.html도 /file로 보낸다.
이유: SSG와 CDN이 같은 말을 해야 한다
Astro가 never로 HTML을 찍는데 Workers가 force-trailing-slash면, 빌드 산출물과 엣지 리다이렉트가 싸운다. 사용자는 주소창에서 한 번 튕기고, 크롤러는 307을 따라가며 크롤 예산을 쓴다. 반대로 none으로 두면 /posts/slug/가 404나 SPA 폴백으로 갈 수 있다. “페이지가 있다”와 “캐노니컬이 하나다”는 다른 문제다.
Bot Fight Mode로 AdsBot이 막힌 이슈와는 결이 다르다. 그건 응답 코드·챌린지 쪽이고, 이번은 경로 정규화다. 둘 다 “봇이 HTML을 제대로 읽게”라는 목표를 공유할 뿐, 설정 노브가 다르다.
평가: drop이 이 레포에 맞는 이유
블로그 글 URL을 /category/slug처럼 슬래시 없이 고정하고 싶었다. 사이트맵·내부 링크·canonical도 같은 형태다. 그래서 기본 auto보다 drop이 예측 가능하다. auto는 폴더형 경로에 슬래시를 남긴다. Astro가 폴더 index를 어떻게 내느냐에 따라 혼선이 생길 여지가 있다.
실무적으로는 배포 후 두 요청만 보면 된다.
curl -sI https://seominhyuk.com/posts/workers-trailing-slash/ | head -5
curl -sI https://seominhyuk.com/posts/workers-trailing-slash | head -5
슬래시 있는 쪽이 307(또는 308)로 슬래시 없는 쪽으로 붙고, 본문 쪽은 200이면 의도대로다. Location이 자기 자신으로 돌거나 200이 양쪽에 동시에 나오면 설정을 다시 본다.
부연: SEO만의 문제가 아니다
광고·분석 픽셀이 “페이지뷰”를 경로 문자열로 집계하면 /a와 /a/가 갈라진다. 내부 로그 대시보드도 같다. 캐노니컬 태그만 믿고 CDN 리다이렉트를 방치하면, 크롤러는 따라가더라도 사람·스크립트·레퍼러가 어긋날 수 있다.
한계도 있다. html_handling은 HTML 자산 패턴에 초점을 둔다. API·바이너리·커스텀 Worker 라우트까지 한 방에 해결하지는 않는다. 미들웨어에서 또 다른 슬래시 규칙을 넣으면 이중 리다이렉트가 난다. 문서의 none은 “내가 전부 직접 한다”는 선언에 가깝다. 정적 블로그만 올리는 구성에서는 과하다.
비슷한 Cloudflare 시행착오를 이미 Bot Fight·이중 배포 글로 적었다. 이번 글의 앵글 해시는 it-trials|html_handling|trailing-slash다. 주제 키워드가 겹치지 않게 경로 정규화만 남겼다.
시니어 운영 시각으로 한 줄만 남기면: 빌드 옵션과 엣지 HTML 처리는 한 쌍으로 커밋한다. 한쪽만 바꾸면 나중에 “왜 프리뷰랑 프로덕션 주소가 다르지?”로 돌아온다.
출처
- HTML handling · Cloudflare Workers docs —
auto/force/drop/none동작 표 (열람: 2026-07-30) - 내부 실측: 레포
wrangler.jsonc의html_handling: "drop-trailing-slash",astro.config.mjs의trailingSlash: 'never'