TIL

2024.03.22 TIL #middleware_matcher

inz1234 2024. 3. 22. 01:14

next.js에는 middleware.ts라는 파일이 있다.

이 middleware.ts 파일은 클라이언트가 서버로 요청을 보낼 때,

중간에서 요청을 가로채서 적절한 처리를 해준 뒤 서버로 전달해주는 역할을 한다.

 

따라서 보통 middleware.ts 파일의 용도는
1) 전역 미들웨어: 모든 요청에 적용되는 미들웨어로, 보안, 로깅 등과 같은 전반적인 기능을 처리한다.

2) 라우트 미들웨어: 클라이언트의 특정 pathname만 protected Route에 접근할 수 있도록 한다.

3) 보안 미들웨어: 보안에 관련된 기능을 처리하는 미들웨어로, CSRF(Cross-Site-Request-Forgery) 공격방지, XSS(Cross-Site-Scripting) 방어, 헤더 보안 설정 등을 수행할 수 있다.

4) 세션 미들웨어: 세션 관리에 사용되는 미들웨어로, 사용자의 세션을 추적하고 관리, 세션 유지를 위한 쿠키설정, 세션 저장 연동 등을 수행할 수 있다.

 

나는 라우트 보호를 위해 middleware.ts 파일을 작성했다.

import { createMiddlewareClient } from "@supabase/auth-helpers-nextjs";
import { NextResponse } from "next/server";

import type { NextRequest } from "next/server";

export async function middleware(req: NextRequest) {
  const res = NextResponse.next();

  const supabase = createMiddlewareClient({ req, res });

  const { data } = await supabase.auth.getSession();
  const { data: userResults, error } = await supabase
    .from("survey")
    .select("*")
    .eq("user_id", data.session?.user.id);

  if (
    !data.session &&
    !req.nextUrl.pathname.startsWith("/login") &&
    !req.nextUrl.pathname.startsWith("/product") &&
    !(req.nextUrl.pathname === "/")
  ) {
    return NextResponse.redirect(new URL("/login", req.url));
  }
  if (data.session && req.nextUrl.pathname.startsWith("/login")) {
    return NextResponse.redirect(new URL("/", req.nextUrl.origin));
  }
  if (
    data.session &&
    userResults?.length !== 0 &&
    req.nextUrl.pathname.startsWith("/survey")
  ) {
    return NextResponse.redirect(new URL("/", req.nextUrl.origin));
  } else {
    return res;
  }
}

export const config = {
  matcher: [
    /*
     * Match all request paths "except for" the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    "/((?!_next/static|_next/image|favicon.ico).*)",
  ],
};

 

- 코드가 꽤 길지만, 

1) 로그인을 하지 않은 사용자가 로그인과 홈 페이지 외의 다른 페이지로 접근하고자 한다면 로그인 페이지로

2) 로그인을 한 사용자가 로그인 페이지로 간다면 홈 페이지로

3) 설문조사하는 로직이 있는데, 이미 설문조사를 한 유저는 다시 설문조사 페이지를 방문하지 못하도록

하는 조건의 미들웨어다.


그런데 문제가 뭐였냐면!

로그인을 하지 않은 상태에서는 홈 페이지의 이미지가 보이지 않았고,

로그인을 해야만 홈 페이지의 이미지가 보여졌다.

 

도대체 문제가 뭐지?

matcher가 문제인가 싶어서 matcher를 봤더니

현재 matcher는 "정적 페이지, next 이미지, favicon 빼고 다" 이 미들웨어를 거친다.

음? 그러면 이미지는 이 미들웨어를 거치지 않는데 왜 로그인을 하지 않으면 안 나오지??

 

한참을 고민했다.


답은... 바롭..... 이미지가 next_image가 아니라 png 파일이었던 것이다^^^^^^^^

하...

export const config = {
  matcher: [
    /*
     * Match all request paths "except for" the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    "/((?!_next/static|_next/image|favicon.ico|.*\\.png$).*)",
  ],
};

결국 정규식에 png 파일을 이렇게 추가를 했고...

홈 페이지에서도 이미지가 잘 나왔다.

 

비록 간단한 문제이긴 했지만, middleware.ts 파일에 대해서 많은 고민을 해볼 수 있었다.

다들.. middleware matcher 조심^^ 정규식 공부하자.