검색 콘솔에서 "중복 — Google이 사용자와 다른 정본을 선택함" 알림이 세 건 왔습니다. 세 사이트 다 로케일 경로(/ko, /en, /ja)로 갈라지는 구조입니다.
같은 알림 세 건이니 같은 원인이라고 생각했습니다. 세 건의 원인이 서로 달랐고, 두 건은 결함이 아니었습니다.
당신은 같은 문구의 알림 세 건을 한 원인으로 묶고 있습니까?
두 건은 성공 신호였습니다
두 사이트는 서브도메인에서 경로형으로 옮기는 이사가 이미 완결된 상태였습니다.
Google이 고른 정본은 우리가 의도한 목적지였습니다. 알림이 이제야 온 건 마지막 크롤이 석 달 전, 즉 리다이렉트를 걸기 전 스냅샷이기 때문이었습니다.
이사 중인 속성에서 이 알림은 성공 신호로 읽어야 합니다. 여기서 시간을 쓰면 아무것도 고쳐지지 않습니다.
세 번째가 진짜였습니다
루트 리다이렉트가 **307(임시)**이었습니다.
googleCanonical = https://<사이트>/ ← Google이 선택(색인됨)
userCanonical = https://<사이트>/ko ← 우리 선언 → "중복"으로 제외307은 통합 신호가 아닙니다. (같은 리다이렉트 지점의 다른 결함은 언어 협상 라우팅 버그, canonical 쪽 별건은 루트 canonical이 하위를 전부 중복으로 만든 이야기에 있습니다.) 그래서 Google은 원 URL(루트)을 정본으로 유지합니다. 표본 10개 중 8개가 같은 패턴이었습니다. **308(영구)**로 바꾸면 목적지로 통합됩니다.
그런데 더 큰 손실이 따로 있었습니다
표본 10개 중 **9개에서 /en이 "Google에 아직 알려지지 않은 URL"**이었습니다.
이유는 단순합니다. /ko의 서버 렌더 HTML에 다른 로케일로 가는 <a> 태그가 하나도 없었습니다. 언어 전환이 클라이언트 사이드였기 때문입니다. 크롤러에게는 도달 경로가 없습니다.
두 가지가 저를 안심시키고 있었는데 둘 다 도달 경로가 아니었습니다.
<link rel="alternate" hreflang>만으로는 색인되지 않습니다.- 사이트맵에 실려 있어도 마찬가지였습니다. 한 사이트는 사이트맵에 URL 3개가 있었고 그중 2개가 미발견이었습니다.
고친 방법은 푸터에 서버 렌더되는 언어 내비게이션을 넣는 것이었습니다.
<nav aria-label="language"><a href="/en">English</a> · <a href="/ja">日本語</a></nav>당신이라면?
307을 308로 바꿔야 합니다. 어디를 고치겠습니까?
- 페이지 컴포넌트의
redirect()— 코드에서 가장 먼저 눈에 띄는 자리. - 프레임워크 설정의
redirects()— 요청이 페이지에 닿기 전에 처리하는 자리. - 둘 다 — 어느 쪽이 실제로 도는지 확인하지 않은 채로.
앱 30개 중 27개는 설정 파일의 redirects()가 루트를 처리하고, 페이지 컴포넌트의 redirect()는 폴백이라 실행되지 않습니다. 페이지 쪽만 고쳐 배포하면 라이브는 그대로 307입니다.
여기서 진단 규칙이 하나 나옵니다. 같은 배포에서 푸터 변경은 반영됐는데 리다이렉트만 안 바뀌었다면, 캐시 문제가 아니라 고친 코드가 도달 불가인 것입니다.
한 사이트는 308로 바꾸면 안 됩니다
전수 적용하려다 멈췄습니다. 한 사이트는 루트에서 방문자의 언어 설정을 보고 분기합니다. 그 응답을 영구로 만들면 처음 온 방문자가 받은 언어가 캐시에 굳습니다.
일괄 수정에서 예외를 하나 찾으면 그건 대개 예외가 하나만 있다는 뜻이 아닙니다. 나머지 29개의 루트 동작을 다시 확인했습니다.
자가진단 세 줄
- 로케일 전환이 클라이언트 사이드입니까? 그렇다면 서버 HTML에 실제
<a href>가 있는지 확인하십시오. 없으면 그 언어는 발견되지 않습니다. - 루트 리다이렉트가 307입니까 308입니까?
curl -sI <루트>로 한 번 보십시오. 통합을 원하면 308입니다. - 리다이렉트를 고쳤는데 라이브가 안 바뀌었습니까? 캐시를 의심하기 전에, 그 코드가 실행되는 자리인지 확인하십시오.
솔직한 부분
이 건에서 제가 가장 오래 붙잡은 건 결함이 아닌 두 건이었습니다. 알림 문구가 같으니 원인도 같을 거라고 가정했기 때문입니다.
그리고 진짜 손실(언어 두 개가 미발견)은 알림에 아예 나오지 않았습니다. 색인 안 된 URL은 "중복"으로도 보고되지 않습니다. 보고되지 않는 손실을 찾으려면 알림을 기다리는 게 아니라 URL을 직접 하나씩 조회해야 했습니다.