본문 바로가기

넥스트

[NextJS] 서버 컴포넌트에서는 어떻게 쿼리 파라미터를 읽을 수 있을까요?

반응형

포스트를 작성하게 된 배경

이번에 진행중인 개인 프로젝트인 명언 웹 사이트에서 사용자가 등록된 명언 카드와 관리자가 등록한 명언 카드 간에 쿼리 파라미터를 사용해서 구분 후 서로 다른 로직을 처리해야 하는 일이 생겼습니다.

 

그런데, 클라이언트 컴포넌트에서는 useSearchParams 라는 리액트 훅을 사용하여 쿼리파라미터를 읽어오거나, window의 location 객체의 searchparams 를 사용하면 간단하게 처리할 수 있는데, 서버 컴포넌트에서는 이 훅들의 사용이 불가능 합니다.

 

따라서 이번 기회에 서버 컴포넌트에서 쿼리 파라미터를 읽는 방법을 정리하면서, 프로젝트에 적용해볼까 합니다.

 

바로 본론으로, 공식문서에 답이 있습니다(단, NextJS 13.0 이상에서만 가능).

블로그 글 보다는 공식 문서를 통해서 해결 방법을 찾아보는 것을 습관화하고 있었는데, 때마침 공식문서에 해당 내용이 있어서 이에 대한 소개를 해보겠습니다. 바로 적용하고 싶으신 분은 이 링크(NextJS 공식문서) 를 바로 참고해주시면 됩니다.

 

NextJS 에서는 서버 컴포넌트의 미들웨어 파일에서 헤더를 설정하는 방법을 알려주었습니다. 즉, 아래와 같이 new Headers 에 request.headers 를 맵핑하면 기존에는 읽기 전용(readonly) 이었던 headers 객체에 접근할 수 있게 됩니다.

 

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  // Clone the request headers and set a new header `x-hello-from-middleware1`
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-hello-from-middleware1', 'hello')
 
  // You can also set request headers in NextResponse.rewrite
  const response = NextResponse.next({
    request: {
      // New request headers
      headers: requestHeaders,
    },
  })
 
  // Set a new response header `x-hello-from-middleware2`
  response.headers.set('x-hello-from-middleware2', 'hello')
  return response
}

 

미들웨어에서 쿼리 파리미터는 어떻게 읽을 수 있나?

그럼 이를 이용해서 특정 경로의 쿼리 파라미터를 읽는 방법에 대해 우선 설명해보겠습니다. 

 

NextJS 에서는 쿼리 파라미터를 읽기 위해서 request 객체를 사용 해야 합니다.

해당 객체에는 클라이언트로 부터오는 요청에 해당 다양한 프로퍼티나 메소드를 가지고 있는데 그 중에서 .nexturl 객체의 .searchParams 객체에 접근하여야 합니다

 

.searchParams 는 params 를 읽기 위한 다양한 메소드를 제공하고 있고, 그 중에서 .get(키) 메소드를 사용하여 특정 쿼리 파라미터의 키에 해당하는 값을 읽어올 수 있습니다. 

 

만일  http://example.com/quotes/authors?type=no-user 이라는 URL 이 있을 때, type 이라는 키에 할당된 no-user 라는 값을 읽으려면 어떻게 할까요?

 

바로 아래와 같이 접근하면 됩니다.

 
  const type = req.nextUrl.searchParams.get('type') || ''
 

 

이렇게 되면 type 이라는 변수에는 no-user 라는 값(value) 이 할당되고, 이를 앞서 알아본 header 에 셋팅하여 원하는 서버 컴포넌트로 이동해서 읽어올 수 있게 됩니다.

 

미들웨어에서 헤더 셋팅하기

그럼 앞서 읽어온 type 을 헤더에 담아서 반환하는 방법을 정리해보겠습니다.

 

requestHeaders 변수에 requset.header 를 new Headers 에 맵핑합니다.

우선 읽기 전용인 기존의 headers 객체를 new Headers 에 맵핑하여 쓰기 전용이 되도록 바꿔주도록 합시다.

export async function middleware(req: NextRequest) {

  const requestHeaders = new Headers(req.headers)
  
 }

 

 

NextResponse 객체의 next 메소드에 요청 헤더 셋팅하기

그 다음에는 NextResponse 라는 기존 response 객체의 확장에 앞서 맵핑한 헤더를 셋팅합니다. 이렇게 되면, 응답 시 해당 헤더를 모든 서버 컴포넌트에서 읽어올 수 있게 됩니다.

 

  const response = NextResponse.next({
    request: {
      headers:requestHeaders
    }

 

 

response 객체에 앞서 읽어온 키-값 셋팅 및 반환

그 다음으로 해주어야 하는 것은  response 객체의 .headers.set 메소드에 접근하여 헤더의 키와 값을 설정해주어야 합니다. 그 뒤에는 모든 서버 컴포넌트에서 해당 헤더를 참조할 수 있도록 reponse 객체를 return 하는 것만 해주면 끝입니다.

  response.headers.set('x-path-type', type)
  return response

 

 

여기서 의문, 특정 경로에서만 미들웨어가 실행되도록 못 하는가?

사실 위에 까지만 해버리면 우리가 원하는 경로에서만 실행되는 것이 아니라 루트(/) 경로를 포함한 모든 경로에서 미들웨어가 실행됩니다. 이렇게 되면 서버 리소스를 아낌없이 사용하기 때문에, 매우 좋지 못한 방식이 되겠죠.

 

따라서 특정 경로에서만 해당 미들웨어가 실행되도록 config 객체에 matcher 를 설정할 것입니다. 이 부분은 앞서 미들웨어에 대한 공식 문서에 가시면 자세한 내용 및 응용 내용을 확인할 수 있으니, 여기서는 사용법만 간단하게 설정하고 마무리하겠습니다.

 

사용 방법은 매우 간단해서 크게 설명할 것은 없습니다. 나머지는 NextJS 내부에서 처리해주니까요. 암튼, 아래와 같이 matcher 프로퍼티의 값으로 매칭하고자 하는 경로를 아래와 같이 적어 줍니다. 

//일치하는 경로만 미들웨어가 실행 됩니다
export const config = {
  matcher: ['/quotes/authors/:path*'],
}
위에서 보면 :path 는 경로 파라미터로 해당 위치에 어떠한 값이 들어오더라도 미들웨어가 실행됩니다.
즉, 위와 같이 작성하게 되면 

"/quotes/authors/abc,  /quotes/authors/a55,  /quotes/authors/abc/434242fsdfsd" 

등등과 같이 작성해도 미들웨어가 실행됩니다.

단,  "/quotes"  "/quotes/auth/" 와 같이 관련없는 경로에서는 미들웨어가 실행되지 않게 됩니다. 
따라서 서버 리소스를 아끼고자 한다면 미들웨어를 필요한 상황에서 사용할 수 있도록 매처를
설정해두는 것을 권장 합니다.

 

서버 컴포넌트에서 헤더 읽어오기

앞서 설정까지 모두 마무리 되었다면, 이제 설정한 헤더의 키를 호출하여 값을 아래와 같이 읽어오기만 하면 됩니다. 추가적으로 설명할 게 없으므로, 이만 마무리 해보겠습니다. 

// 경로: http://example.com/quotes/authors?type=no-user

import { headers } from 'next/headers'

export default async function DetailPage() {

  console.log(headers()?.get('x-path-type')) // no-user

  return (
    <article>
      // -- 다양한 코드들
    </article>
  )
}

 

 

참고로 next/header 가 무엇인지 궁금하시다면, 여기 공식문서를 참고해보세요

https://nextjs.org/docs/app/api-reference/functions/headers

 

Functions: headers | Next.js

API reference for the headers function.

nextjs.org

 

반응형