개발 slecs

레거시 게시물 URL을 새 주소로 자동 이동

목차

지난 세션에서 콘텐츠 경로 구조를 /{slug} 에서 /p/{id} 로 개편했는데, 이때 이전 URL들이 깨지면 사용자가 북마크한 링크나 외부 인링크가 모두 dead link 가 되어 버린다. 특히 검색 엔진이 그 페이지들을 색인 해제하려고 기다리는 동안 SEO 손실이 누적된다. 그래서 301 리다이렉트를 사용해 레거시 경로를 새로운 구조로 자동 이동시키는 처리를 추가했다.

URL 마이그레이션은 단순한 기술 작업이 아니다

초반에는 "그냥 서버에서 리다이렉트 로직 추가하면 되겠지" 정도로 가볍게 생각했는데, 사실 이건 여러 관계자의 우려가 얽힌 일이었다. 마케팅팀은 기존 URL 이 검색 결과에서 사라질까봐 걱정했고, 개발팀은 임시 리다이렉트(302)로 처리하면 캐싱 문제가 생길까봐 우려했으며, 운영팀은 "그동안 어느 URL 이 제일 많이 접근됐는지 추적해야 마이그레이션 우선순위를 정할 수 있다"고 요청했다. 결국 이런 작업은 기술만의 문제가 아니라 조직이 이전 시스템과 새 시스템 사이의 다리를 얼마나 안전하게 건설할 것인가라는 의사결정 문제였다.

왜 301 인가

HTTP 리다이렉트 상태 코드는 여러 가지인데, 각각의 의미가 다르다:

  • 301 (Moved Permanently): "이 리소스가 새 위치로 영구히 이동했다" — SEO 가중치가 기존 URL 에서 새 URL 로 이전되고, 브라우저와 검색 엔진도 이걸 영구 이동으로 기록한다.
  • 302 (Found): "일시적으로 다른 위치에 있다" — 검색 엔진이 계속 원본 URL 을 색인하려고 하고, 캐싱도 신중하게 한다.
  • 307 (Temporary Redirect): 302와 유사하지만 HTTP 메서드를 변경하지 않는다 (POST 요청이면 리다이렉트 후에도 POST 유지).

우리 경우엔 정말로 URL 구조 자체를 버렸으므로 301 이 맞다. 기존 링크를 계속 지원한다는 건 일시적이 아니라 영구적 정책이고, 검색 엔진에도 "이 페이지는 이제 저 주소에만 있다"고 명확히 알려야 SEO 페널티를 피할 수 있다.

Astro 에서의 동적 라우팅 패턴

변경된 파일이 src/pages/[...slug].astro 다. Astro 의 파일 기반 라우팅에서 [...slug] 는 모든 URL 을 catch 한다는 뜻이다. 즉:

/{slug}          → [...slug].astro 에서 params.slug = ""
/{slug}/posts    → params.slug = "posts"
/{slug}/foo/bar  → params.slug = "foo/bar"

이 핸들러 안에서 들어온 slug 패턴을 분석해서, 만약 레거시 형식이라면 새로운 ID 기반 경로로 리다이렉트 하는 식이다. 예를 들어:

// 레거시 URL 인식
if (slug.match(/^[a-z-]+$/)) {  // 순수 slug 형식
  const id = await lookupIdBySlug(slug);
  if (id) {
    return redirect(301, `/p/${id}`);
  }
}

이렇게 하면 이전에 구글에서 "내 게시물" 이라는 키워드로 검색되던 /my-post URL 이 /p/12345 로 부드럽게 이동되고, 검색 엔진은 그 페이지의 랭킹을 새 주소로 옮기기 시작한다.

실제로 마주친 고민들

처음엔 "모든 구 URL 을 메모리에 캐시해두고 빠르게 매칭하자"고 했는데, 게시물이 수만 개라면 시작 시간과 메모리 사용이 문제가 된다. 결국 데이터베이스 쿼리가 필요한데, 모든 요청마다 DB 를 조회하면 성능이 떨어진다. 그래서 최종적으로는 Redis 같은 캐시 레이어를 두거나, 아니면 마이그레이션 초기 몇 주간은 리다이렉트를 적극 활용하고 시간이 지나면서 트래픽이 줄어들 걸 기대하는 방식을 택했다.

또 다른 issue 는 "리다이렉트 체인"이었다. 만약 어떤 이유로 /old-slug/newer-slug 로 리다이렉트되고, /newer-slug 가 또 /p/{id} 로 리다이렉트된다면, 사용자는 3개의 HTTP 요청을 거쳐야 한다. 검색 엔진은 이런 체인을 따라가지 않을 수도 있으므로, URL 매핑을 정규화하고 직접 최종 주소로 가도록 깔끔하게 정리했다.

팀 관점에서의 의사결정

이 작업을 하면서 느낀 건, 작은 URL 리다이렉트 하나도 "누가 이걸 알아야 하는가" 를 먼저 정해야 한다는 것이었다. 마케팅팀은 언제부터 이전 링크를 권장하지 않을 건지 알아야 했고, 운영팀은 301 리다이렉트 로그를 분석해서 영향받은 사용자 수를 보고해야 했으며, QA 팀은 "모든 레거시 URL 이 제대로 리다이렉트되는가"를 체계적으로 테스트해야 했다. 기술 리더로서 이런 의존성들을 미리 매핑하고 각 팀이 무엇을 언제까지 해야 하는지 명확히 하는 게 결국 whole system 이 부드럽게 돌아가는 열쇠였다.

레거시 시스템과의 이별은 깔끔할수록 좋지만, 그 과정에서 기존 사용자들을 배려하는 리다이렉트 같은 장치를 빠뜨리면 신뢰를 잃는다. 이번 작업으로 "마이그레이션은 기술 변경이 아니라 조직적 전환"이라는 걸 다시 한 번 배웠다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.