Next.js middleware 알아보기

lionloopy·2024년 11월 25일
0

오늘의 공부

목록 보기
4/22
post-thumbnail

Next.js

Next.js는 리액트를 위해 만든 자바스크립트 웹 프레임워크로,
리액트에는 없는 SSR, CSR, ISR과 같은 기능을 제공
한다.

여기서!

개발언어:
개발하기 위한 기본적인 도구, 컴퓨터가 이해하고 실행하기 위한 언어

프레임워크:
특정 개발 언어를 기반으로 만들어진, 개발 작업을 더 쉽게 하고 구조를 제공하는 틀
Python 기반: Django, Flask.
JavaScript 기반: React, Angular, Vue.js.
Java 기반: Spring, Hibernate.
PHP 기반: Laravel, Symfony

middleware란

미들웨어란,

  • 처음 유저가 보낸 요청과 종착지 사이에 있는 소프트웨어이다.

  • 페이지를 렌더링하기 전에 서버측에서 실행되는 함수이다.

  • 특정 요청 전에 무언가를 수행할 수 있게 해주는 기능

  • request 객체와 response 객체에 접근할 수 있으며, 이를 활용해 요청 정보를 받아와 부가적인 처리를 하고, 응답 객체에 무언가를 추가하거나 응답을 변경할 수 있다.

  • 페이지 렌더링 전에 인증을 확인하거나 요청을 확인할 때

  • 요청 데이터를 사전에 처리하거나, 특정 api 요청을 수행하거나, 캐시를 관리할 때

  • 요청에 대한 응답을 변환하거나 에러 처리를 할 때

유저의 정보를 DB에 보낼 때 중간에서 검증 함수를 거친다면, 그 함수가 미들웨어이다.

사용 방법

  1. next.js 최신 버전 설치
  2. 루트 또는 src 디렉토리에 middleware.ts 또는 middleware.js 파일을 만든다.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// 이 함수는 `await`을 사용하는 경우 `async`로 표시될 수 있습니다.
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/about-2', request.url))
}

// 자세한 내용은 아래의 "경로 일치"를 참조하세요.
export const config = {
  matcher: '/about/:path*',
}
  • matcher을 사용하면 특정 경로에서 middleware가 실행되도록 필터링 할 수 있다.
  • matcher 구성에는 정규식을 사용할 수 있다.
export const config = {
  matcher: [
    '/:path((?!api|.*\\..*|_next/static|_next/image|favicon.ico|_next/public).*)',
  ],
};

응답 조작하기

  • redirect: 오는 요청에 대한 경로를 다른 URL 로 redirect 시킨다.
  • rewrite: 오는 요청에 대한 경로는 유지하고, rewrite 하는 URL의 응답을 보여준다.
  • set Header: request header, response header, cookie를 설정할 수 있다.

사용해보기

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { NextURL } from 'next/dist/server/web/next-url';

/**
 * 지정한 페이지로 이동
 * @param url req.nextUrl.clone
 * @param LOGIN_PAGE_URL 이동할 URL
 */
const goToLoginPage = (url: NextURL, LOGIN_PAGE_URL: string) => {
  url.pathname = LOGIN_PAGE_URL;
  return NextResponse.redirect(url);
};

/** 세션 인증에 필요한 현재시간 반환 */
const NowTime = () => {
  const nowTime = new Date()
    .toISOString()
    .replace(/[^0-9]/g, '')
    .slice(0, 14)
    .toString();
  return nowTime;
};

export async function middleware(req: NextRequest) {
  const sessionId = req.cookies.get('session')?.value;
  const email = req.cookies.get('email')?.value;
  const url = req.nextUrl.clone();

  const LOGIN_PAGE_URL = '/auth/auth/login';
  const AUTH_CHECK_API_URL = '/api/auth_check/authcheck';

  // 현재 요청된 URL이 로그인 페이지인지 확인
  const isLoginPage = req.nextUrl.pathname === LOGIN_PAGE_URL;

  // 쿠키에 세션 이나 이메일이 없다면 로그인 페이지로 이동
  if ((!sessionId || !email) && !isLoginPage) {
    return goToLoginPage(url, LOGIN_PAGE_URL);
  }

  try {
    const apiUrl = `${process.env.API_URL}${AUTH_CHECK_API_URL}`;
    const cookie = `session=${sessionId}`;

    // 세션 검증 요청
    // axios로 구현 불가, fetch만 cookie가 정상적으로 담김
    const response = await fetch(apiUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Cookie: cookie,
      },
      body: JSON.stringify({
        // email: email,
        email: 'slneoi',
        time: NowTime(),
      }),
    });

    const result = await response.json();

    // API 응답이 정상이 아니라면 로그인 페이지로 리다이렉트
    if (!response.ok) {
      goToLoginPage(url, LOGIN_PAGE_URL);
    }

    // API 응답안에 role 값이 있는 지 체크
    if (result) {
      // 정상응답, 요청한 페이지로 이동
      return NextResponse.next();
    } else {
      // 비정상응답, 로그인 페이지로 리다이렉트
      goToLoginPage(url, LOGIN_PAGE_URL);
    }
  } catch (error) {
    // API 호출 실패 시 로그인 페이지로 리다이렉트
    goToLoginPage(url, LOGIN_PAGE_URL);
  }
}

// matcher에 매칭되는 경로로 접근하는 경우, middleware 실행
export const config = {
  matcher: [
    '/:path((?!api|.*\\..*|_next/static|_next/image|favicon.ico|_next/public).*)',
  ],
};

참고

https://velog.io/@real-bird/Next.js-middleware
https://velog.io/@pds0309/nextjs-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%EB%9E%80
https://velog.io/@hwisaac/NextJS-Middleware

profile
기록은 담백하게, 성장은 빠르게! 🐘

0개의 댓글