본문 바로가기

개발/React

(짧) Nextjs fetch를 사용할 때 User-Agent 트래킹하기

반응형

 

Nextjs를 사용하면서 캐싱을 활용하기 위해서는 내부적으로 제공해주는 fetch를 활용하는 것이 일반적이다.

(다만 실무에서 Nextjs의 캐싱을 제대로 활용할 수 있을까 하면 쉽지 않아보인다.)

 

그렇게 Nextjs에서 제공해주는 fetch를 사용하면서 진입 유저 분석을 위해 User Agent를 수집하다보면 이상한 점이 보인다.

 

기존에 User Agent로서 익숙한 이름들이 아니라 모든 요청이 undici 라는 User Agent값으로 넘어오는데, 이는 node 라이브러리 중 하나로 HTTP 요청을 더 좋은 성능으로 수행할 수 있도록 해주는 라이브러리라고 한다.

 

Nextjs에서는 실제로 Node 버전이 18버전보다 낮으면 이를 동일하게 수행해주는 polyfill을 사용한다고한다.

 

https://nextjs.org/docs/app/api-reference/config/next-config-js/httpAgentOptions

 

next.config.js: httpAgentOptions | Next.js

Next.js will automatically use HTTP Keep-Alive by default. Learn more about how to disable HTTP Keep-Alive here.

nextjs.org

 

https://github.com/vercel/next.js/discussions/57875

 

Next.js 14 `fetch` requests show `user_agent=undici` in the backend logs · vercel next.js · Discussion #57875

Although Undici is removed in Next.js 14, the fetch requests coming to the backend server from the Next.js instance in Vercel (or a local instance) show user_agent=undici. Is this a misconfiguratio...

github.com

 

 

 

그렇다면 이렇게 모든 요청에 대한 User Agent가 undici로 넘어오면 어떻게 실제 User Agent를 찾아낼 수 있을까?

 

필자가 사용한 방법은 다음과 같다.

 

// middleware

const originalUserAgent = request.headers.get('user-agent') || '';
response.headers.set('x-real-user-agent', originalUserAgent);

 

 

먼저 middleware 단에서는 실제 진입 유저의 user agent가 제대로 적용되어있다.

 

따라서 이때 미리 user-agent를 다른 헤더값으로 넣어둔다.

 

const customFetch = (props) => {
  const [url, options] = props;
  const headers = { ...options?.headers };

  if (isServer()) {
    try {
      const { headers: nextHeaders } = await import('next/headers');
      const realUserAgent = nextHeaders().get('x-real-user-agent') || '';

      if (realUserAgent) {
        headers['User-Agent'] = realUserAgent;
      }
    } catch (e) {
      console.error('Headers import error:', e);
    }
  } else {
    const clientUserAgent = Cookies.get('x-real-user-agent') || '';

    if (clientUserAgent) {
      headers['User-Agent'] = clientUserAgent;
    }
  }

  const response = await fetch(`${apiURL}${url}`, {
    cache: 'no-store',
    ...options,
    headers,
  });

 

 

 

이후 fetch 함수를 확장해 사용하기 위한 레이어함수를 만들고, 이 안에서 서버/클라이언트의 요청을 캐치해서 fetch의 header에 있는 User Agent에 middleware에서 저장해둔 값을 넣어주는 방식이다.

 

next/headers로부터 headers 정보를 가지고오는 방식은 서버컴포넌트에서만 가능하기때문에 isomorphic 하게 사용하기 위해서는 서버환경일때만 해당 값을 import하는 동적 import 방식을 활용하면 두 환경에서 모두 호환이 가능한 코드를 구현할 수 있게 된다.

 

이렇게 작성하여 레이어 함수를 확장해 사용하면 default로 들어있던 undici가 사라지고 실제 진입 User Agent값이 잘 적용된다.

반응형