주소 이동 (커스텀 리다이렉트) 연동
어드민(mysite.roottale.com)의 설정 > 주소 이동에서 운영자가 정의한 임의
경로 이동 규칙(/old-event → /promo)을 사이트 미들웨어로 적용합니다. 코드
수정 없이 고객이 직접 규칙을 추가·수정·삭제할 수 있습니다.
두 종류의 주소 이동이 있습니다.
- 글 주소 변경 자동 301 — 블로그 글의 슬러그를 바꾸면 자동으로 옛 주소가
새 주소로 이어집니다. 글 라우트에서 처리되며 별도 설정이 필요 없습니다
(
blog.md의postRedirectPath참고). - 커스텀 리다이렉트(이 문서) — 글이 아닌 임의 경로를 옮깁니다. 라우팅 이전 단계인 미들웨어에서만 가로챌 수 있어, 아래 설정이 필요합니다.
규칙은 GET /v1/cms/public/redirects 로 내려오며 활성 규칙만 포함됩니다
(api-reference.md). 출발 경로는 정규화된 사이트 내부 절대 경로, 도착지는
내부 경로 또는 절대 URL, 상태는 301(영구) 또는 302(임시)입니다.
미들웨어 설정
@roottale/cms-renderer-next 의 createRedirectMiddleware 를 프로젝트 루트
middleware.ts 에 마운트합니다. 규칙을 자동 캐시(기본 60초)하며, API 실패 시
트래픽을 막지 않고 통과시킵니다(fail-soft).
// middleware.ts
import { NextResponse } from "next/server";
import { createRedirectMiddleware } from "@roottale/cms-renderer-next/routes";
const redirects = createRedirectMiddleware({
apiKey: process.env.ROOTTALE_API_KEY!,
// apiBase, siteId, cacheTtlMs 는 선택.
});
export async function middleware(req: Request) {
return (await redirects(req)) ?? NextResponse.next();
}
// Next 내부·API·알려진 정적 자산만 제외합니다. 점 포함 경로를 전부 막으면
// `/old.html`·`/foo.php` 같은 레거시 마이그레이션 리다이렉트가 동작하지
// 않으므로, 자산 확장자만 명시적으로 제외합니다.
export const config = {
matcher: [
"/((?!_next/|api/|.*\\.(?:ico|png|jpg|jpeg|gif|svg|webp|css|js|txt|xml|json|woff2?|map)$).*)",
],
};
ROOTTALE_API_KEY는 블로그 조회와 같은 키입니다. 서버 전용 — 절대 브라우저에 노출하지 마세요.- 매칭은 정확 경로 일치입니다(와일드카드 없음). 출발 경로의 앞/뒤 슬래시와 한글 percent-encoding 차이는 자동 정규화해 비교합니다.
- 도착지가 내부 경로면 요청 origin 기준 절대 URL 로 변환해 리다이렉트합니다.
- 매칭이 없으면
null을 반환하므로NextResponse.next()로 통과시키세요.
캐시와 즉시성
규칙은 미들웨어가 TTL(기본 60초) 동안 캐시합니다. 운영자가 규칙을 바꾸면
최대 TTL 만큼 뒤 반영됩니다. 더 빠른 반영이 필요하면 cacheTtlMs 를 줄이세요
(요청당 API 호출이 늘어납니다).
const redirects = createRedirectMiddleware({
apiKey: process.env.ROOTTALE_API_KEY!,
cacheTtlMs: 10_000, // 10초
});
직접 호출 (미들웨어 없이)
규칙 목록만 필요하면 fetchRedirects 로 직접 가져올 수 있습니다.
import { fetchRedirects } from "@roottale/cms-client/server";
const rules = await fetchRedirects({ apiKey: process.env.ROOTTALE_API_KEY! });
// [{ id, fromPath, toTarget, statusCode }]