- 분야: FE
- 기술 스택: React · TypeScript(TSX) · Next.js 호환 라우팅
문제와 원인
필터 목록 URL에는 q·category·topic이 있었지만 상세 링크에서 복귀 주소가 누락됐다. 돌아가기 링크는 document.listPath만 가리켜 상세를 다녀오면 기본 목록으로 돌아갔다.
수정 전 코드
PublicTheoryDirectory
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
href={article.href}
목록 복귀·이전·다음 단원
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
href={document.listPath}
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
{previous && <Link className="outline-button" href={previous.href}>← 이전 단원</Link>}
{next && <Link className="primary-button" href={next.href}>다음 단원 →</Link>}
수정 후 코드
PublicTheoryDirectory
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
href={theoryDetailHref(article.href, theoryListHref(listPath, { q: search, category, topic: activeTopic }))}
목록 복귀·이전·다음 단원
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
const returnHref = safeTheoryReturnHref(document.listPath, returnTo);
href={returnHref}
{previous && <Link className="outline-button" href={theoryDetailHref(previous.href, returnHref)}>← 이전 단원</Link>}
{next && <Link className="primary-button" href={theoryDetailHref(next.href, returnHref)}>다음 단원 →</Link>}
주소 생성·검증
theoryListHref가 세 필터를 포함한 목록 주소를 만들고, theoryDetailHref가 상세 링크의 기존 쿼리를 보존하면서 return_to를 추가한다. 상세와 이전·다음 단원 이동에서도 같은 복귀 주소를 전달한다.
복귀 시 safeTheoryReturnHref는 같은 origin과 정확한 listPath를 검사한 뒤 세 필터만 다시 구성한다. 필터별 값은 200자로 제한한다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
type Filters = { q?: string; category?: string; topic?: string };
export function theoryListHref(listPath: string, filters: Filters) {
const query = new URLSearchParams();
for (const key of ["q", "category", "topic"] as const) {
if (filters[key]) query.set(key, filters[key]!.slice(0, 200));
}
return listPath + (query.size ? "?" + query : "");
}
export function theoryDetailHref(href: string, returnTo: string) {
const [path, query] = href.split("?");
const params = new URLSearchParams(query);
params.set("return_to", returnTo);
return path + "?" + params;
}
export function safeTheoryReturnHref(listPath: string, value?: string) {
if (!value || !value.startsWith("/") || value.startsWith("//")) {
return listPath;
}
try {
const url = new URL(value, "https://modumunje.com");
if (url.origin !== "https://modumunje.com" || url.pathname !== listPath) {
return listPath;
}
return theoryListHref(listPath, {
q: url.searchParams.get("q") ?? undefined,
category: url.searchParams.get("category") ?? undefined,
topic: url.searchParams.get("topic") ?? undefined,
});
} catch {
return listPath;
}
}
검증 결과
원본 전후 함수와 링크 표현식에 같은 7개 입력을 넣었다. 정상 필터 4개에서 누락이 4개에서 0개로 줄고, 잘못된 복귀 주소 3/3개는 기본 목록으로 이동했다.
좌우로 이동해 전체 내용을 확인하세요. 키보드: ←·→, Home·End
| 입력 조건 | 수정 전 | 수정 후 |
|---|---|---|
| 검색어 지정 | 검색어 누락 | q 유지 |
| 과목 지정 | 과목 누락 | category 유지 |
| 단원 지정 | 단원 누락 | topic 유지 |
| 검색어·과목·단원 함께 지정 | 세 필터 누락 | 세 필터 유지 |
//로 시작하는 다른 출처 주소 | 기본 목록 | 기본 목록 |
| 다른 출처의 절대 주소 | 기본 목록 | 기본 목록 |
다른 경로 /admin | 기본 목록 | 기본 목록 |
검색어 정규화, 과목 데이터 모델링의 이해, 단원 정규화를 각각 지정하거나 함께 지정한 네 입력과 잘못된 주소 세 입력을 로컬 Node에서 각 1회 다시 실행했다. 네 필터 입력은 쿼리를 보존했고 잘못된 주소는 기본 목록을 반환했다.