앞단 리다이렉트 목록이 새로 만든 페이지를 잡아먹는다

/about, /contact, /privacy 를 새로 만들었다. 빌드는 정상이었는데 배포하고 열어보니 셋 다 다른 데로 튕겼다.

301  /about
301  /contact
301  /privacy

배경

이 도메인은 원래 다른 앱이 쓰던 주소다. 그 앱을 하위 도메인으로 옮기고 여기에 허브를 올렸다.

옮기고 나면 옛 주소로 들어오는 유입이 죽는다. 검색 결과도 북마크도 여전히 옛 주소를 가리키니 앞단에 리다이렉트를 하나 세웠다.

const PAGES = ["about", "predict", "market", "privacy", "guide", "contact", "disclaimer", "result"];

if (MOVED.has(first)) {
  return Response.redirect(TTAKOCHAN + url.pathname + url.search, 301);
}

옛 앱에 있던 페이지 이름을 죽 적어뒀다.

여기서 대개 의심하는 것

나는 빌드를 의심했다. 파일이 실제로 생성됐는지 봤다.

dist/about/index.html
dist/contact/index.html
dist/privacy/index.html

다 있었다. 그다음 정적 파일 서빙 설정을 봤다. 멀쩡했다.

리다이렉트 코드를 보고 나서야 알았다. 옛 앱에도 about, contact, privacy 가 있었다. 흔한 이름이니 겹치는 게 당연했다.

새로 만든 페이지가 제 이름 때문에 밀려났다.

원인

앞단 리다이렉트는 정적 파일보다 먼저 돈다. 그래야 옛 주소를 가로챌 수 있으니 당연한 순서다.

그런데 그 목록에 적힌 건 옛 앱에 있던 이름이다. 새 사이트에 같은 이름의 페이지를 만들면 목록이 먼저 잡는다.

흔한 페이지 이름은 겹칠 수밖에 없다. about, contact, privacy, terms, login. 옛 사이트에도 있고 새 사이트에도 생긴다.

처방

목록에서 뺀다.

const PAGES = ["predict", "market", "guide", "disclaimer", "result"];

뺀 이름은 이제 새 사이트의 페이지로 열린다. 옛 주소로 들어오던 사람은 내용이 다른 새 페이지를 보게 되는데, 아무것도 없는 것보다는 낫다.

개인정보처리방침은 특히 이 도메인에서 열려야 한다. 광고 심사가 보는 주소가 여기다. 다른 도메인으로 301 되면 안 된다.

테스트로 고정한다

같은 실수가 다시 나면 배포 전에 잡히게 해뒀다.

test("apex 자체 페이지는 타코쨩으로 안 넘긴다", async () => {
  for (const p of ["/about", "/contact", "/privacy"]) {
    const res = await worker.fetch(new Request("https://ttakochan.com" + p));
    expect(res.status).not.toBe(301);
  }
});

리다이렉트 목록은 나중에 또 건드린다. 그때 실수로 다시 넣는 걸 막으려는 테스트다.

확인할 때 주의할 것

고치고 배포한 뒤 찍었더니 이렇게 나왔다.

200  /about
200  /contact
301  /privacy

하나만 안 고쳐진 것처럼 보인다. 같은 수정, 같은 배포인데.

캐시를 우회해서 다시 찍었더니 이번엔 순서가 달랐다.

200 301 301

같은 주소가 요청마다 다르게 답했다. CDN 엣지가 순차적으로 갱신되는 중이었다. 어떤 엣지는 새 코드를, 어떤 엣지는 옛 코드를 돌리고 있었다.

4초 간격으로 12번, 이어서 10번을 더 찍으니 전부 200 으로 안정됐다.

여기서 시간을 날렸다. 진짜 버그를 고친 직후에 전파 지연을 만나니 수정이 안 먹은 줄 알고 코드를 다시 뒤졌다.

왜 헷갈리나

증상이 코드에서 멀다. 404 가 아니라 301 이다. 파일이 없어서 못 찾는 게 아니라 다른 데로 보내진 건데, 브라우저에서는 그냥 “이상한 페이지가 떴다” 로 보인다.

리다이렉트를 짜둔 시점과 페이지를 만든 시점도 멀다. 몇 달 전에 적어둔 목록을 기억하고 있을 리가 없다. 흔한 이름일수록 잘 겹치는데, 하필 흔한 이름일수록 새 사이트에도 만들게 된다.

이런 걸 미리 피하려면

목록에 왜 이 이름이 있는지 주석으로 남긴다. 나는 이렇게 적어뒀다.

/** 옛 앱 경로만 골라 하위 도메인으로 넘긴다.
 *  about·privacy·contact 는 뺐다. apex 는 이제 자체 페이지를 갖는다. */

목록 방식보다는 접두사 방식이 낫다. 옛 주소를 전부 /legacy/ 같은 접두사 아래로 몰 수 있으면 이름이 겹칠 일 자체가 없다. 이미 흩어진 뒤라면 못 쓴다.

새 페이지를 만들면 배포 전에 한 번 찍어본다. 로컬 빌드에서 파일이 생겼는지가 아니라 배포된 주소가 200 을 주는지를 본다. 이 둘은 다른 얘기다.

남은 것

이 목록을 언제 지울 수 있는지는 모르겠다. 옛 주소로 들어오는 유입이 아직 있는지 확인해야 판단이 서는데, 그걸 안 재고 있다. 재기 시작해야 지울 수 있다.

← 블로그 목록