Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Upstash Redis を使用して Next.js ブログにビュー カウンターを追加する

すべてのブログ投稿に閲覧数が表示される Lee のブログに触発されて、私も自分のページでも同様のことをしたいと思いました。新しいアプリ ルーターで Next.js 13 も使用していますが、ページ ビューを mysql データベースに保存する代わりに、Upstash Redis を使用します。

これは、これから構築するものの例です。ホームページ上の各カードには、そのカードのビュー数が表示されます。

Upstash Redis を使用して Next.js ブログにビュー カウンターを追加する

Redis を使用する理由

Redis には、重複排除とカウンターの増加を簡単にする 2 つの優れたコマンドがすでに付属しています。

より正確なカウンターを取得するために、カウンターの増加をデバウンスしたいと考えています。ユーザーがページを更新する場合、カウンタは 1 回だけインクリメントされる必要があります。 Redis の SET を使用すると、これを非常に簡単に行うことができます。 コマンド。 NX があります キーがまだ存在しない場合にのみキーを設定するオプションと EX 指定された秒数後にキーを期限切れにするオプション。これらのオプションの両方を組み合わせることで、1 人のユーザーが指定された時間枠内でカウンタを複数回増加させないようにすることができます。

2 番目のコマンドは INCR です。 これにより、指定されたキーがアトミックに 1 ずつインクリメントされます。

Redis のセットアップ

Upstash でのデータベースのセットアップは簡単で、1 日あたり 10,000 件のリクエストが無料で含まれます。ここで新しいデータベースを作成できます。文字通り数秒しかかかりません。その後、下にスクロールして REST をコピーします。 .env.local への接続の秘密 ファイル:

.env.local
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=

Next.js

Redis データベースができたので、カウンターの実装を開始できます。まず @upstash/redis をインストールする必要があります:

pnpm add @upstash/redis

ページビューを保存するには、2 つのコンポーネントが必要です。 API ルートとクライアント コンポーネント。 API ルートから始めましょう。

/api/incr.ts

Upstash と @upstash/redis Vercel のエッジ機能と互換性があるため、まず必要なものをすべてインポートし、redis をセットアップし、ランタイムを edge に設定します。 .

新しいファイル /api/incr.ts を作成します 次のコードを追加します。

/api/incr.ts
import { NextRequest, NextResponse } from "next/server";
 
import { Redis } from "@upstash/redis";
 
const redis = Redis.fromEnv();
 
export const config = {
 runtime: "edge",
};

次に、スラッグまたは同様の識別子をリクエストボディで渡すように要求します。存在しない場合は、400 が返されます。 ステータス コード。

/api/incr.ts
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 アドレスを直接保存する必要がなくなります。

/api/incr.ts
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 これにより、特定の IP アドレスが過去 24 時間以内にページを閲覧したかどうかを確認する簡単な方法が得られます。

/api/incr.ts
const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
 nx: true,
 ex: 24 * 60 * 60,
});
if (!isNew) {
 new NextResponse(null, { status: 202 });
}

最後に行うことは、指定されたスラッグのカウンターをインクリメントすることです。 INCR を使用します。 このためのコマンド:

/api/incr.ts
await redis.incr(["pageviews", "projects", slug].join(":"));
return new NextResponse(null, { status: 202 });

参考までに、完全なコードはここにあります

/app/[slug]/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/[slug]/page.tsx

最後に行う必要があるのは、ReportView を追加することです。 追跡したいページのコンポーネント:

/app/[slug]/page.tsx
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 も追加する必要があります。 config をページ コンポーネントに追加します。これにより、ページはリクエストごとではなく 60 秒ごとに再検証されます。

/app/[slug]/page.tsx
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 でお知らせください。


  1. アイテムをあるリストから別のリストにポップ&プッシュする方法-Redis RPOPLPUSH | BRPOPLPUSH

    このチュートリアルでは、あるキーに保存されているリスト値の最後の要素を削除して返す方法と、redisデータストアの別のキーに保存されているリスト値の最初の位置に同じ要素を挿入する方法について学習します。このために、Redis RPOPLPUSHを使用します およびBRPOPLPUSH コマンド。 RPOPLPUSHコマンド このコマンドは、ソースキーに格納されているリスト値の末尾(end)から要素を削除して返し、宛先キーに格納されているリスト値の先頭(start)に同じ要素を挿入するために使用されます。ソースキーが存在しない場合は、nil値が返され、操作は実行されません。宛先キーが存在し

  2. Flutter、サーバーレスフレームワーク、Upstash(REDIS)を備えたフルスタックサーバーレスアプリ-パート2

    このチュートリアルシリーズのパート2へようこそ。最初のパートでは、Upstash、Serverless Framework、およびRedisを使用してRESTAPIを構築する方法を説明しました。 このパートでは、Flutterを使用してモバイルアプリケーションを構築し、RESTAPIエンドポイントを使用します。 始めましょう🙃 まず、フラッターをコンピューターにインストールして実行する必要があります フラッター IDEで新しいフラッタープロジェクトを作成し、任意の名前を付けます。 pubspec.yamlを開きます flutterプロジェクトのルートディレクトリにあるファイルを