แรงบันดาลใจจากบล็อกของ Lee ซึ่งทุกโพสต์ในบล็อกแสดงจำนวนการดูที่มี ฉันต้องการทำสิ่งที่คล้ายกันสำหรับเพจของฉัน ฉันยังใช้ Next.js 13 กับเราเตอร์แอปใหม่ แต่แทนที่จะจัดเก็บการดูหน้าเว็บในฐานข้อมูล mysql ฉันจะใช้ Upstash Redis
นี่คือตัวอย่างสิ่งที่เราจะสร้าง การ์ดแต่ละใบในหน้าแรกจะแสดงจำนวนการดูที่มี

ทำไมต้อง Redis?
Redis มาพร้อมกับคำสั่งที่ยอดเยี่ยม 2 คำสั่งที่ทำให้การขจัดข้อมูลซ้ำซ้อนและเพิ่มตัวนับเป็นเรื่องเล็กน้อย
เพื่อให้ได้ตัวนับที่แม่นยำยิ่งขึ้น ฉันต้องการหักล้างการเพิ่มขึ้นของตัวนับ หากผู้ใช้รีเฟรชเพจ ตัวนับควรเพิ่มขึ้นเพียงครั้งเดียวเท่านั้น เราสามารถทำสิ่งนี้ได้อย่างง่ายดายด้วย 04 ของ Redis คำสั่ง มันมี 19 ตัวเลือกที่จะตั้งค่าคีย์เฉพาะในกรณีที่ยังไม่มีและ 23 ตัวเลือกที่จะหมดอายุคีย์หลังจากระยะเวลาไม่กี่วินาทีที่กำหนด ด้วยการรวมตัวเลือกทั้งสองนี้เข้าด้วยกัน เราจึงสามารถมั่นใจได้ว่าผู้ใช้รายเดียวจะไม่เพิ่มเวลานับถอยหลังหลายครั้งภายในกรอบเวลาที่กำหนด
คำสั่งที่สองคือ 35 ซึ่งจะเพิ่มคีย์ที่กำหนด 1 อะตอม
การตั้งค่า Redis
การตั้งค่าฐานข้อมูลบน Upstash เป็นเรื่องง่ายและมีคำขอ 10,000 คำขอต่อวันฟรี! คุณสามารถสร้างฐานข้อมูลใหม่ได้ที่นี่ ใช้เวลาเพียงไม่กี่วินาทีเท่านั้น หลังจากนั้นเลื่อนลงและคัดลอก 48 ความลับในการเชื่อมต่อไปยัง 55 ของคุณ ไฟล์:
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN= ถัดไป js
ตอนนี้เรามีฐานข้อมูล Redis แล้ว เราก็สามารถเริ่มใช้งานตัวนับได้ เราจำเป็นต้องติดตั้ง @upstash/redis ก่อน:
pnpm add @upstash/redis เพื่อจัดเก็บการดูเพจ เราจำเป็นต้องมีสององค์ประกอบ เส้นทาง API และส่วนประกอบของลูกค้า เริ่มจากเส้นทาง API กันก่อน
/api/incr.ts
อัพสแตชและ 68 เข้ากันได้กับฟังก์ชัน Edge ของ Vercel ดังนั้นก่อนอื่น เราจะนำเข้าทุกสิ่งที่เราต้องการ ตั้งค่า Redis และกำหนดค่ารันไทม์เป็น 75 .
สร้างไฟล์ใหม่ 86 และเพิ่มรหัสต่อไปนี้:
import { NextRequest, NextResponse } from "next/server";
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
export const config = {
runtime: "edge",
};
ต่อไปเราจะต้องส่งตัวบุ้งหรือตัวระบุที่คล้ายกันไปยังเนื้อหาคำขอ หากไม่มีอยู่ เราจะส่งคืน 91 รหัสสถานะ
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 ของผู้ใช้ด้วย เราสามารถทำได้โดยใช้109 ทรัพย์สิน เราจะแฮชที่อยู่ IP โดยใช้ 118 อัลกอริธึมและจัดเก็บไว้ในฐานข้อมูล วิธีนี้ทำให้เราไม่จำเป็นต้องจัดเก็บที่อยู่ 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 แรกที่กล่าวถึงข้างต้น ใช้ 127 ร่วมกับ131 และ 140รหัส> ให้วิธีง่ายๆ แก่เราในการตรวจสอบว่าที่อยู่ IP ใดมีการดูหน้าเว็บภายใน 24 ชั่วโมงที่ผ่านมาหรือไม่:
const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
nx: true,
ex: 24 * 60 * 60,
});
if (!isNew) {
new NextResponse(null, { status: 202 });
}
สิ่งสุดท้ายที่ต้องทำคือเพิ่มตัวนับสำหรับทากที่กำหนด เราจะใช้ 154 คำสั่งสำหรับสิ่งนี้:
await redis.incr(["pageviews", "projects", slug].join(":"));
return new NextResponse(null, { status: 202 }); เพื่อเป็นข้อมูลอ้างอิง คุณสามารถค้นหาโค้ดทั้งหมดได้ที่นี่
/app/[กระสุน]/view.tsx
ต่อไป เรามาสร้างส่วนประกอบไคลเอนต์ขนาดเล็กที่ส่งคำขอไปยังเส้นทาง api ที่เราเพิ่งสร้างขึ้นทุกครั้งที่ติดตั้ง จากนั้นส่วนประกอบนี้สามารถฝังลงในเพจใดก็ได้ที่เราต้องการติดตาม
/app/[กระสุน]/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
สิ่งสุดท้ายที่เราต้องทำคือเพิ่ม 169 ส่วนประกอบของหน้าที่เราต้องการติดตาม:
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>
);
}
จากนี้ไปการเข้าชมทั้งหมดจะถึง 173 จะถูกติดตามและตัวนับจะเพิ่มขึ้นสำหรับผู้เข้าชมที่ไม่ซ้ำแต่ละคนใน 24 ชั่วโมงที่ผ่านมา
การแสดงมุมมอง
การติดตามการดูเป็นสิ่งที่ดี แต่เรายังต้องการแสดงมุมมองเหล่านั้นต่อสาธารณะด้วย มาดูกันว่าเราจะทำเช่นนั้นได้อย่างไร
เพื่อที่จะแสดงจำนวนการดู เราจำเป็นต้องค้นหาจากฐานข้อมูล เราสามารถทำได้โดยใช้ 185 คำสั่ง เราควรเพิ่ม 194 ด้วย กำหนดค่าให้กับองค์ประกอบของหน้า เพื่อให้หน้าได้รับการตรวจสอบอีกครั้งทุกๆ 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