모든 블로그 게시물이 조회수를 표시하는 Lee의 블로그에서 영감을 받아 mypage에도 비슷한 작업을 수행하고 싶었습니다. 또한 새로운 앱 라우터와 함께 Next.js 13을 사용하고 있지만 페이지 뷰를 mysql 데이터베이스에 저장하는 대신 Upstash Redis를 사용할 예정입니다.
다음은 우리가 구축할 내용의 예입니다. 홈페이지의 각 카드에는 조회수가 표시됩니다.

왜 Redis인가요?
Redis에는 이미 중복 제거 및 카운터 증가를 간편하게 해주는 2가지 훌륭한 명령이 제공됩니다.
보다 정확한 카운터를 얻기 위해 카운터 증가를 디바운싱하고 싶습니다. 사용자가 페이지를 새로 고치면 카운터는 한 번만 증가해야 합니다. Redis의 SET를 사용하면 이 작업을 정말 쉽게 수행할 수 있습니다. 명령. NX입니다 아직 존재하지 않는 경우에만 키를 설정하는 옵션과 EX 주어진 시간(초) 후에 키를 만료시키는 옵션입니다. 이 두 가지 옵션을 결합함으로써 단일 사용자가 주어진 기간 내에 카운터를 여러 번 증가시키지 않도록 할 수 있습니다.
두 번째 명령은 INCR입니다. 주어진 키를 원자적으로 1씩 증가시킵니다.
Redis 설정
Upstash에 데이터베이스를 설정하는 것은 쉽고 하루에 10,000개의 요청을 무료로 포함합니다! 여기에서 새 데이터베이스를 생성할 수 있습니다. 문자 그대로 단 몇 초밖에 걸리지 않습니다. 그런 다음 아래로 스크롤하여 REST을 복사하세요. .env.local에 대한 연결 비밀 파일:
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN= Next.js
이제 Redis 데이터베이스가 있으므로 카운터 구현을 시작할 수 있습니다. 먼저 @upstash/redis를 설치해야 합니다:
pnpm add @upstash/redis 페이지 조회수를 저장하려면 두 가지 구성 요소가 필요합니다. API 경로 및 클라이언트 구성 요소입니다. API 경로부터 시작해 보겠습니다.
/api/incr.ts
업스태시 및 @upstash/redis Vercel의 엣지 기능과 호환되므로 우선 필요한 모든 것을 가져오고 redis를 설정하고 런타임을 edge로 구성합니다. .
새 파일 /api/incr.ts 만들기 그리고 다음 코드를 추가하세요:
import { NextRequest, NextResponse } from "next/server";
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
export const config = {
runtime: "edge",
};
다음으로 요청 본문에 슬러그 또는 유사한 식별자를 전달해야 합니다. 존재하지 않으면 400을 반환합니다. 상태 코드입니다.
export default async function incr(req: NextRequest): Promise<NextResponse> {
const body = await req.json();
const slug = body.slug as string | undefined;
if (!slug) {
return new NextResponse("Slug not found", { status: 400 });
}
// more to come here
}
그런 다음 사용자의 IP 주소도 가져와야 합니다. req.ip를 사용하여 이를 수행할 수 있습니다. 재산. SHA-256을 사용하여 IP 주소를 해시합니다. 알고리즘을 적용하여 데이터베이스에 저장합니다. 이렇게 하면 보안 문제가 될 수 있는 IP 주소를 직접 저장할 필요가 없습니다.
const ip = req.ip;
// Hash the IP and turn it into a hex string
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(ip));
const hash = Array.from(new Uint8Array(buf))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
이제 위에서 언급한 첫 번째 redis 명령을 사용해 보겠습니다. SET 사용 NX과 함께 및 EX 지난 24시간 동안 특정 IP 주소가 페이지를 조회했는지 쉽게 확인할 수 있는 방법을 제공합니다.
const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
nx: true,
ex: 24 * 60 * 60,
});
if (!isNew) {
new NextResponse(null, { status: 202 });
}
마지막으로 해야 할 일은 주어진 슬러그에 대한 카운터를 증가시키는 것입니다. 우리는 INCR을 사용하겠습니다. 이를 위한 명령:
await redis.incr(["pageviews", "projects", slug].join(":"));
return new NextResponse(null, { status: 202 }); 참고로 여기에서 전체 코드를 찾을 수 있습니다.
/app/[슬러그]/view.tsx
다음으로, 마운트될 때마다 방금 생성한 API 경로에 요청을 보내는 작은 클라이언트 구성 요소를 만들어 보겠습니다. 그런 다음 이 구성요소를 추적하려는 모든 페이지에 삽입할 수 있습니다.
/app/[slug]/view.tsx"use client";
import { useEffect } from "react";
export const ReportView: React.FC<{ slug: string }> = ({ slug }) => {
useEffect(() => {
fetch("/api/incr", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ slug }),
});
}, [slug]);
return null;
}; /app/[슬러그]/page.tsx
마지막으로 해야 할 일은 ReportView을 추가하는 것입니다. 추적하려는 페이지의 구성요소:
import { ReportView } from "./view";
type Props = {
params: {
slug: string;
};
};
export default function Page({ params }: Props) {
return (
<div>
<ReportView slug={params.slug} />
{/* Add your page content here */}
</div>
);
}
이제부터 /app/[slug]를 방문하는 모든 사람 지난 24시간 동안 각 고유 방문자에 대해 추적되고 카운터가 증가합니다.
뷰 표시
조회수를 추적하는 것은 좋지만 공개적으로 표시하고 싶습니다. 어떻게 할 수 있는지 살펴보겠습니다.
조회수를 표시하려면 데이터베이스에서 조회수를 조회해야 합니다. GET을 사용하여 이를 수행할 수 있습니다. 명령. revalidate도 추가해야 합니다. 모든 요청이 아닌 60초마다 페이지의 유효성을 다시 검사하도록 페이지 구성 요소에 구성을 추가합니다.
type Props = {
params: {
slug: string;
};
};
export const revalidate = 60
export default function Page({ params }: Props) {
const views = await redis.get<number>(["pageviews", "projects", params.slug].join(":")) ?? 0
return ...
} 마지막 단어
chronark.com에서 이에 대한 전체 예를 확인하세요. 코드는 GitHub에서 사용할 수 있습니다. 특히 관련 내용은 다음과 같습니다.
- API 경로
- 추적 구성요소
- 조회수 로드 중
더 많은 페이지뷰 분석에 관심이 있으시면 Twitter나 Discord를 통해 알려주시기 바랍니다.