Server Action의 redirect가 catch에 잡혀 리다이렉트가 안 된 이유
문제 발생
Server Action에서 저장에 성공하면 상세 페이지로 보내려고 했는데, 리다이렉트가 되지 않고 "알 수 없는 오류" 화면이 떴습니다.
"use server";
export async function createPost(formData: FormData) {
try {
const post = await savePost(formData);
redirect(`/posts/${post.slug}`); // ❌ try 안
} catch (error) {
console.error(error);
return { message: "저장에 실패했습니다." };
}
}로그에는 NEXT_REDIRECT라는 낯선 오류가 찍혀 있었습니다.
원인 분석
redirect()는 값을 반환하는 함수가 아니라 오류를 던지는 함수입니다. Next.js 공식 문서가 그대로 적습니다 — redirect()를 호출하면 NEXT_REDIRECT 오류를 던지고 그것이 던져진 라우트 세그먼트의 렌더링을 종료합니다.
그래서 try 블록 안에서 호출하면 바로 아래 catch가 그 오류를 잡아버립니다. 프레임워크가 받아야 할 신호를 우리 코드가 가로챈 것입니다. 문서도 못박습니다 — redirect는 오류를 던지므로 try/catch를 쓸 때는 try 블록 바깥에서 호출해야 합니다.
해결 방안
try바깥으로 뺍니다. 성공 여부를 변수로 받고, 리다이렉트는 블록이 끝난 뒤에 합니다.
"use server";
export async function createPost(formData: FormData) {
let slug: string;
try {
const post = await savePost(formData);
slug = post.slug;
} catch (error) {
console.error(error);
return { message: "저장에 실패했습니다." };
}
redirect(`/posts/${slug}`); // ✅ try 바깥
}-
return을 붙일 필요는 없습니다. 문서의 안내대로redirect는 TypeScript의never타입을 쓰기 때문에return redirect()로 쓸 필요가 없습니다. 붙여도 무해하지만 필수는 아닙니다. -
상태 코드가 왜 307/308인지 알아둡니다. 전통적으로 쓰던 302는 많은 브라우저가 원래 요청 메서드와 무관하게 POST를 GET으로 바꿉니다.
/users로 POST한 것이/people로 GET이 되면 의미가 달라집니다. 307은 메서드를 보존하고, 영구 이동인 308도 마찬가지입니다. -
Server Action의 폼 제출은 예외입니다. 문서에 따르면 Server Action 폼 제출은 303 응답을 써서 브라우저가 GET으로 따라가게 합니다. 그리고 JavaScript를 쓸 수 있으면 HTTP 리다이렉트 대신 클라이언트 사이드 내비게이션을 수행합니다.
-
영구 이동은
permanentRedirect입니다. 307 대신 308을 보냅니다. URL 구조를 바꿨을 때 검색엔진에 알리는 용도입니다. -
히스토리 동작을 의도대로 고릅니다. 기본값이 상황마다 다릅니다 — Server Action에서는
push, 그 외에서는replace입니다. Server Component에서는type인자가 아무 효과가 없습니다.
import { redirect, RedirectType } from "next/navigation";
redirect("/dashboard", RedirectType.replace);- 이벤트 핸들러에서는 쓰지 않습니다. 문서가 명시합니다 — Client Component에서 렌더링 과정 중에는 호출할 수 있지만 이벤트 핸들러에서는 안 됩니다. 그 자리에는
useRouter를 씁니다.
"use client";
const router = useRouter();
<button onClick={() => router.push("/posts")}>목록</button>- 렌더 이전에 보내야 하면 다른 도구입니다. 문서가
next.config.js의redirects나 Proxy를 가리킵니다. 인증 리다이렉트처럼 페이지에 들어가기도 전에 판단되는 것은 그쪽이 맞습니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.