ในคู่มือนี้ เราจะเดินผ่านการจัดการ session ในแอป Next.js โดยใช้ Upstash Redis โดยเรียนรู้ว่า "session" หมายถึงอะไรในเว็บแอปพลิเคชัน ทำไม Redis ถึงเป็นตัวเลือกยอดนิยมสำหรับการจัดการ session วิธีตั้งค่าฐานข้อมูล Upstash Redis และสุดท้ายวิธีผสานรวมเข้ากับแอปพลิเคชัน Next.js
Session คืออะไร?
ในเว็บแอปพลิเคชัน "session" เป็นกลไกจัดเก็บฝั่งเซิร์ฟเวอร์ที่ชั่วคราว ใช้เพื่อรักษาสถานะของการโต้ตอบของผู้ใช้กับแอปพลิเคชันข้ามหลาย HTTP requests ในช่วงเวลาที่กำหนด
เนื่องจาก HTTP เป็นโปรโตคอลที่ไม่มีสถานะ (stateless) หมายความว่าแต่ละ request เป็นอิสระและไม่ "จำ" การโต้ตอบก่อนหน้า sessions จึงช่วยให้เซิร์ฟเวอร์ติดตามและจัดเก็บข้อมูลเฉพาะผู้ใช้ เช่น สถานะการรับรองตัวตน การตั้งค่าของผู้ใช้ หรือกิจกรรมใดๆ ของผู้ใช้ในช่วงเวลาที่อยู่บนเว็บไซต์
Sessions ทำงานโดยปกติโดยการจัดเก็บ session ID ที่ไม่ซ้ำกันฝั่ง client โดยปกติใน cookie เซิร์ฟเวอร์ใช้ ID นี้เพื่อดึงข้อมูลที่เกี่ยวข้องกับ user session จาก session storage เช่น Redis ในบล็อกนี้ ทุกครั้งที่ผู้ใช้โต้ตอบกับไซต์
Session ในเว็บแอปพลิเคชันเป็นวิธีที่ยอดเยี่ยมในการจัดการการโต้ตอบและการจัดการสถานะของผู้ใช้ต่อไปนี้:
- User Authentication: Sessions ช่วยรับรองตัวตนผู้ใช้และจำสถานะล็อกอินข้ามหน้าหรือแม้หลัง refresh
- Personalization: Sessions อนุญาตให้เซิร์ฟเวอร์จัดเก็บและดึงข้อมูล เช่น ความชอบของผู้ใช้ สถานะการรับรองตัวตน ฯลฯ
- Security: การจัดการ session อย่างถูกต้องสามารถเพิ่มความปลอดภัยของแอป เช่น ป้องกัน CSRF และรับรองว่าผู้ใช้ที่ไม่ได้รับอนุญาตไม่เข้าถึงพื้นที่ที่จำกัด
ทำไมต้อง Redis สำหรับการจัดการ Session?
ทำไมไม่ :)
มีหลายเหตุผลในการใช้ Redis เป็น session store สำหรับการจัดการ session นี่คือข้อได้เปรียบบางประการที่เกิดจากโครงสร้างของ Redis:
Data Architecture: Redis เป็น in-memory key-value store คู่คีย์-ค่าเหล่านี้สามารถจัดเก็บใน hashes ได้ โดย hash เป็นประเภท record ที่มีโครงสร้างเป็นชุดของ field-value pairs โครงสร้างนี้เหมาะอย่างยิ่งกับข้อมูลการจัดการ session เพื่อรักษาข้อมูล session ทั้งหมด เช่น username, user preference ฯลฯ ในรูปแบบ key-value ใน hash ต่อ user session
Data Expiry: Redis มีฟังก์ชัน built-in สำหรับลบข้อมูลที่หมดอายุ นี่ช่วยให้เว็บแอปพลิเคชันเก็บ user sessions ให้มีเวลาจำกัด
Low Latency: เนื่องจากลักษณะ "in-memory" ของมัน Redis เร็วมาก นั่นคือเหตุผลที่มันมักถูกใช้สำหรับ user sessions และ cache data
Scalability: Redis สร้างขึ้นเพื่อจัดการปริมาณข้อมูลมากและ high-throughput traffic
นอกจากนี้ เราสามารถเปรียบเทียบ Redis กับหนึ่งในวิธีที่พบบ่อยที่สุดในการจัดเก็บข้อมูล user session คือ client-side cookies เพื่อตัดสินใจว่าเราจะเลือกเส้นทางไหนในเว็บแอปพลิเคชันของเรา ข้อได้เปรียบบางประการของ Redis ในฐานะ session storage เหนือ client-side cookies:
Less vulnerable to user tampering: Cookies มองเห็นได้โดยผู้ใช้และสามารถถูกจัดการโดยผู้ใช้ Redis อนุญาตให้เราปกป้องข้อมูลผู้ใช้จากการถูกจัดการโดยผู้ใช้
Less data transferred between client and server: เนื่องจากเราจัดเก็บข้อมูล session ทั้งหมดใน Redis เราไม่จำเป็นต้องจัดเก็บอะไรในเครื่อง client
Storing only "SessionId" in client machine: หากเราใช้ Redis เราแค่ต้องการ sessionId สำหรับแต่ละ request เพื่อรู้ว่าคำขอนี้อยู่ใน session ไหน
การสร้าง Upstash Redis Database
ก่อนจะกระโดดเข้าสู่การตั้งค่า Upstash Redis เราควรเข้าใจข้อได้เปรียบของ Upstash Redis ก่อน ไม่สมเหตุสมผลที่จะใช้เครื่องมือที่เราจะใช้โดยไม่เข้าใจว่าทำไมควรใช้มันใช่ไหม?
มาดูข้อได้เปรียบหลักของการใช้ Upstash Redis:
Serverless: Upstash Redis เป็นฐานข้อมูล serverless คุณไม่ต้องดูแล infrastructure กังวลเกี่ยวกับการ scale ของฐานข้อมูล หรือการกำหนดค่า low-level ใดๆ คุณแค่สร้างฐานข้อมูลและใช้งาน
Global Data Distribution: Upstash อนุญาตให้คุณปรับใช้ Redis instance ใน regions ใกล้ผู้ใช้ของคุณ ลด latency ลงอีก ไม่ว่าผู้ใช้จะอยู่ที่ไหน session storage ก็รวดเร็วและตอบสนอง
Pay as you Go: ไม่มีค่าเข้าประตู คุณจ่ายแค่สิ่งที่คุณใช้ คุณสามารถดูรายละเอียดราคาได้
โอเค ถ้าเราไม่มีคำถามเพิ่มเติมเกี่ยวกับทำไมเราใช้ Upstash Redis สำหรับการจัดการ session เราสามารถสร้างฐานข้อมูล Upstash Redis ได้
เราจะสร้างฐานข้อมูล Redis ผ่าน Upstash console
มาสร้างฐานข้อมูล Redis โดยการคลิกปุ่ม "Create Database" บทช่วยสอนนี้จะแสดงอีกครั้งว่าการสร้างฐานข้อมูล Upstash Redis นั้นง่ายและรวดเร็วแค่ไหน
ใน modal ที่ปรากฏ เราจะเลือกชื่อสำหรับฐานข้อมูลของเรา และเลือก region สำหรับมัน อาจจะดีกว่าถ้าเลือก region เดียวกับ service ของคุณ
หลังจากคลิกปุ่ม next เราจะเลือก pricing plan Pay as you go with max budget limit คือโปรดของผม!
ตอนนี้ฐานข้อมูล Redis ของเราพร้อมแล้ว เราสามารถเห็น database endpoint, password สำหรับเชื่อมต่อกับฐานข้อมูล และ port บน Redis dashboard เราจะต้องการข้อมูลนี้เมื่อเราต้องการเชื่อมต่อกับฐานข้อมูลจากเว็บแอปพลิเคชัน

นั่นคือทั้งหมด!
การใช้ Upstash Redis ใน Nextjs App
มาดูว่า Redis จะทำงานภายในโครงสร้างพื้นฐานของเว็บแอปพลิเคชันอย่างไร:
เราได้รับ request จาก browser ของ client โดยไม่มี sessionId
เนื่องจากไม่มี sessionId ใน request เราสร้าง sessionId หนึ่งตัวและสร้าง hash ใน Redis
คืนค่า sessionId เป็น cookie ใน response ไปยังเครื่อง client
เมื่อเราได้รับ HTTP request ใหม่พร้อม sessionId เราดึงข้อมูล session ที่จำเป็นจาก Redis และใช้มันเมื่อตอบกลับ client
นี่คือ sequence diagram ของ service และการเชื่อมต่อกับ Redis เพื่อให้เห็นกระบวนการชัดเจนขึ้น:

ถ้าทุกอย่างดี เราสามารถสร้าง Nextjs app ได้โดยการรันคำสั่งต่อไปนี้ในเทอร์มินัล เว้นแต่คุณมี Nextjs app อยู่แล้ว
npx create-next-app@latest <project-name>
ตอนนี้เราต้องติดตั้ง Upstash Redis Typescript SDK
cd <project-name> npm install @upstash/redis
หลังจากติดตั้ง dependency ที่จำเป็นแล้ว เราสามารถสร้าง interface สำหรับจัดการ session ID ใน cookies ของ browser ผู้ใช้ และโต้ตอบกับ Upstash Redis, session storage ของแอปของเราได้แล้ว
เราจะ implement interface นี้ในไฟล์ /app/lib/sessionManager.tsx
import { Redis } from '@upstash/redis' import { cookies } from 'next/headers' export const redis = new Redis({ url: '<UPSTASH-REDIS-URL>', token: 'UPSTASH-REDIS-TOKEN', }) type SessionId = string; type Key = 'userName' | 'sessionStatus'; // other keys of the session data can be added. export async function getSessionId(): SessionId | undefined { const cookieStore = await cookies(); return cookieStore.get("session-id")?.value; } async function setSessionId(sessionId: SessionId): void { const cookieStore = await cookies(); cookieStore.set("session-id", sessionId); } export async function getSessionIdAndCreateIfMissing() { const sessionId = await getSessionId(); if (!sessionId) { const newSessionId = crypto.randomUUID(); await setSessionId(newSessionId); return newSessionId; } return sessionId; } export async function get(key: Key, username: string = "") { const sessionId = await getSessionId(); if (!sessionId) { return null; } return await redis.hget(`session-${username}-${sessionId}`, key); } export async function getAll(username: string = "") { const sessionId = await getSessionId(); if (!sessionId) { return null; } return await redis.hgetall(`session-${username}-${sessionId}`); } export async function set(key: Key, value: string, username: string = "") { const sessionId = await getSessionIdAndCreateIfMissing(); await redis.hset(`session-${username}-${sessionId}`, { [key]: value }); return redis.expire(`session-${username}-${sessionId}`, 900); }
มาตรวจสอบฟังก์ชันเหล่านี้
getSessionId: เราจะจัดเก็บ session ID ใน cookies ของ browser ผู้ใช้ ฟังก์ชันนี้เพื่อดึง session ID จาก browser cookies ที่ส่งไปยัง API ภายใน HTTP call
setSessionId: ฟังก์ชันนี้ตั้งค่า session ID cookie ให้เป็น session ID พารามิเตอร์ที่ให้มา
getSessionIdAndCreateIfMissing: ฟังก์ชันนี้เรียก
getSessionIdเพื่อดึง session ID ที่มีอยู่จาก cookies และตั้งค่า UUID แบบสุ่มใหม่เป็น session ID ใหม่ เว้นแต่จะมี session ID อยู่ใน browser ของผู้ใช้แล้ว ฟังก์ชันนี้ยังเพิ่ม session ID ใหม่ลงใน cookies เพื่อส่งกลับไปที่ browsergetSessionData: เราจะเรียกฟังก์ชันนี้เพื่อดึงข้อมูล session จาก Redis มันจะดึงข้อมูล session ของ key ที่ให้มาจาก Upstash Redis และคืนค่า
getAllSessionData: ฟังก์ชันนี้ดึงข้อมูล session ทั้งหมด มันดึง key-value pairs ทั้งหมดของ session hash จาก Upstash Redis
setSessionData: เราจะตั้งค่า key-value pairs ของ session ที่ให้มาในฟังก์ชันนี้
เนื่องจาก utility functions สำหรับจัดการ session IDs และ session storage ผ่าน Upstash Redis พร้อมแล้ว เราสามารถ implement API ที่ใช้ฟังก์ชันเหล่านี้ได้แล้ว
API จะเรียบง่ายมาก มันจะรับ username จาก path เมื่อได้รับ request มันจะตรวจสอบก่อนว่ามี session ID ใน cookies หรือไม่ หากไม่มี session ID ใน cookies มันจะสร้าง ID ใหม่และตั้งค่าใน cookies ใน response หากมี session ID มันจะตรวจสอบว่ามี key ใน Upstash Redis ใน hash ที่แทน session หรือไม่ หากไม่มี มันจะสร้าง key-value pairs ใน hash นั้น
มาเขียนโค้ดกัน!
API จะถูกสร้างโดยใช้ app routers ของ Nextjs
เราควรสร้างไฟล์ภายใต้ app/api/user/[username]namedroute.tsx`
import * as sessionStore from '../../lib/session' export async function GET(request: Request,{ params }: { params: Promise<{ user: string }> }){ const userName = (await params).user; const sessionId = await sessionStore.getSessionIdAndCreateIfMissing(); const sessionStatus = await sessionStore.get('sessionStatus', userName); if(sessionStatus == null) { console.log('There is no active session.'); await sessionStore.set('sessionStatus', 'ACTIVE', userName); } return Response.json({ userName: userName, sessionId: sessionId }); }
ไฟล์ route นี้จะอนุญาตให้ Nextjs resolve request ที่ส่งไปที่ <URL>:3000/api/user/<username> ไปยัง HTTP methods ที่กำหนดภายในตัวมันเอง
ตอนนี้ เราจะเห็นมันทำงาน จะรัน Nextjs app โดยไปที่ root directory จากเทอร์มินัลและรันคำสั่งต่อไปนี้:
npm run dev
ตอนนี้ เราสามารถเปิด API endpoint, https://localhost:3000/api/user/noah บน browser เมื่อคุณเปิด คุณควรเห็น username และ session ID ที่คืนค่า:
{"userName":"noah","sessionId":"804814dc-10fc-4b0a-a4c1-321f4b54d399"}
ถ้าคุณคลิกขวาและ inspect คุณจะเห็น session-id ที่ตั้งค่าใน cookies โดยไปที่แท็บ "Application"

เราสามารถตรวจสอบ Upstash Redis ได้ว่ามี session ถูกสร้างในฐานข้อมูลหรือไม่ เพื่อตรวจสอบ เราควรกลับไปที่ Upstash Redis console, เปิดฐานข้อมูล Redis และเปิดแท็บ Data Browser
แท็บ Data Browser จะแสดง session data ตามที่แสดงด้านล่าง

สรุป
การจัดการ sessions ใน Next.js app ด้วย Upstash Redis นำเสนอโซลูชันที่ scalable และ efficient ในบล็อกโพสต์นี้ เราสร้าง Nextjs app และผสานรวมกับ Upstash Redis เพื่อใช้เป็น session management storage
ด้วยการตั้งค่าฐานข้อมูล Redis และผสานรวมเข้ากับ Next.js อย่างราบรื่น คุณสามารถจัดการ session storage ได้อย่างมีประสิทธิภาพโดยไม่มีความซับซ้อนของ server-side แบบดั้งเดิม วิธีนี้เหมาะสำหรับนักพัฒนาที่มองหาประสิทธิภาพและความเรียบง่ายในการจัดการ session
หวังว่าคู่มือนี้จะให้เส้นทางที่ชัดเจนสำหรับการนำ Upstash Redis ไปใช้เป็น session store ที่น่าเชื่อถือในแอปพลิเคชัน Next.js ของคุณ