라우팅과 미들웨어
라우팅과 미들웨어
라우팅이란
웹 애플리케이션에서 URL에 따라 어떤 페이지나 컴포넌트를 보여줄지 결정하는 시스템.
app/ => app router 사용
page.js => 메인 홈페이지 (/)
about/ => about 디렉토리
page.js => about 페이지 (/about)
blog/ => blog 디렉토리
[id]/ => 동적 경로 세그먼트
page.js => 개별 블로그 포스트 페이지 (/blog/any-post-title)
동적 라우팅 (기본 형식)
URL의 일부가 변수처럼 작동할 수 있도록 해줌. []
를 활용하여 나타냄. 예컨데 app router의 product 디렉토리에서 동적 라우팅을 활용하고 있다면, 사용자에게 url이 product/id번호
의 형식으로 나타나는 것.
1
2
3
4
5
6
7
8
9
10
11
// app/product/[id]/page.tsx
interface ProductPageProps {
params: {
id: string;
};
}
export default function ProductPage({ params }: ProductPageProps) {
return <div>{params.id}</div>;
}
근데 이건 하나의 세그먼트(슬래시로 구분된 부분)만 캡쳐할 수 있음. 따라서 main 안에 sub, 그 안에 또 sub 이렇게 계단식으로 url을 계속 넣고싶다면, 아래처럼 동적 세그먼트를 여러개 따로 써야됨.
app/
category/
[main]/
[sub]/
page.tsx
근데 이렇게 하면 세그먼트의 개수와 순서를 정확히 고정해야됨. 만약 sub값이 없다면 바로 404 에러가 발생함. 예를 들어서 내가 블로그를 만들었는데 클라이언트가 sub값 없이 main값 까지만 접근했다면 404 에러가 발생하는 것. category/main
캐치올 세그먼트
그래서 이를 보완하기 위해 등장한게 캐치올 세그먼트. 얘는 그냥 유동적으로 지가 알아서 처리해주는거임. slug란, 간편한 url로 사용자 친화적 url을 의미함. 참고로 id도 그렇고 slug도 그렇고 그냥 예시를 보여주기 위해 이 단어들을 사용한거지, 대괄호 안에 아무 단어나 넣어도 됨. 대신 캐치올을 사용하고 싶다면 단어를 대괄호로 감싸고 단어 앞에 ...
을 붙여야함. 캐치올을 선택적으로 사용하고 싶다면 [[...]]
와 같은 형식으로 사용하면 됨.
app/
category/
[...slug]/
page.tsx
근데 404 페이지를 기본적으로 보여주는게 낫지 않나?
라는 생각이 들었음. 블로그든 쇼팡몰이든 간에 사용자가 잘못된 근데 사이트 특성마다 존재 안 함 이라는 대목 보다 찾고 계신 페이지가 이건가요? 라고 보여지는게 ux 측면에서 더 낫다고 함. 이건 사이트의 특성마다 다르니.. ㅇㅅㅇ
그 외..
병렬 라우트
하나의 url에서 여러 페이지나 컴포넌트를 동시에 렌더링 할 수 있게 해줌. 디렉토리명 앞에 @
표시를 붙여서 사용함.
그럼 비동기처리랑 뭔 차인데?
비동기처리로도 데이터를 패칭하는 과정 중에 다른 작업을 할 수 있으니까 이 두 작업의 차이점이 뭔지가 궁금했음. 사용자 경험에서 두 작업간에 있어 차이는 별로 없지만 비동기처리를 사용하면 단일 페이지내에서 컴포넌트 로딩의 흐름을 제어하는거고, 병렬 라우트를 사용하면 페이지/레이아웃 수준에서 네비게이션의 상태를 관리하는 것.
인터셉팅 라우트
말그대로 현재 레이아웃에서 다른 라우트 내용을 가로채서 표시한다는 의미.
(.)
- 같은 레벨에서 가로채기(..)
- 한 레벨 위에서 가로채기(..)(..)
- 두 레벨 위에서 가로채기(...)
- 루트에서 가로채기
app/
feed/
page.ts
(.)photo/[id]/
page.ts => /photo/123 (feed 내부에서 모달로 표시)
미들웨어란
요청이 완료되기전에(서버에 도달했을 때) 코드를 실행할 수 있게 해주는 기능. 즉 누군가 어떤 페이지를 열려고 할 때, Next.js가 그 요청을 “처리하기 전에” 잠깐 가로채서 검사하거나 리디렉션, 인증 등을 처리할 수 있게 해주는 것. 예를 들어 로그인 여부에 따라 페이지를 다르게 처리하고 싶다면 아래와 같이 적을 수 있음.
1
2
3
4
5
6
7
8
9
10
11
12
13
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const isLoggedIn = Boolean(request.cookies.get('token'))
if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}