Computer >> Máy Tính >  >> Lập trình >> Redis

Phòng chờ cho ứng dụng Next.js của bạn bằng các chức năng của Edge

Trong bài đăng này, chúng tôi sẽ tạo phòng chờ cho ứng dụng Next.js của bạn bằng cách sử dụng các chức năng Vercel Edge và Upstash Redis.

Bạn có thể kiểm tra mã nguồn và ứng dụng demo.

Phòng chờ?

Phòng chờ rất hữu ích khi bạn muốn giới hạn số lượng khách truy cập đang hoạt động vào trang web của mình để không làm quá tải tài nguyên của bạn.

Trong quá trình triển khai của chúng tôi, bạn sẽ có thể đặt số lượng khách truy cập hoạt động tối đa. Sẽ có hai tham số để kiểm soát lưu lượng truy cập:

  • Dung lượng trang web tối đa:Số lượng khách truy cập tối đa vào trang web cùng một lúc?
  • Thời gian chờ phiên tối đa:Số giây tối đa mà khách truy cập có thể không sử dụng

Bước 1:Thiết lập dự án

Tạo ứng dụng Next.js:

examples git:(master) ✗ npx create-next-app@latest --typescript

✔ What is your project named? … nextjs-waiting-room

Creating a new Next.js app in /Users/enes/dev/examples/nextjs-waiting-room.

Cài đặt Upash-redis:

npm install @upstash/redis

Bước 2:Triển khai

Vercel hỗ trợ các chức năng của Edge thông qua phần mềm trung gian Next.js. Vì vậy, chúng tôi sẽ thêm _middleware.ts dưới pages/api/ . Mã phần mềm trung gian chặn tất cả các yêu cầu được thực hiện tới / api. Để biết các cấu hình khác nhau, hãy xem tại đây.

Cập nhật trang pages/api/_middleware.ts như bên dưới:

import { Redis } from "@upstash/redis";
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";

const COOKIE_NAME_ID = "__waiting_room_id";
const COOKIE_NAME_TIME = "__waiting_room_last_update_time";
const UPSTASH_REDIS_REST_TOKEN = "REPLACE_HERE";
const UPSTASH_REDIS_REST_URL = "REPLACE_HERE";
const TOTAL_ACTIVE_USERS = 10;
const SESSION_DURATION_SECONDS = 30;

const redis = new Redis({
  url: UPSTASH_REDIS_REST_URL,
  token: UPSTASH_REDIS_REST_TOKEN,
});

export async function middleware(req: NextRequest, ev: NextFetchEvent) {
  const cookies = req.cookies;
  let userId;
  if (cookies[COOKIE_NAME_ID] != null) {
    userId = cookies[COOKIE_NAME_ID];
  } else {
    userId = makeid(8);
  }

  const size = await redis.dbsize();
  console.log("current capacity:" + size);
  // there is enough capacity
  if (size < TOTAL_ACTIVE_USERS) {
    return getDefaultResponse(req, userId);
  } else {
    // site capacity is full
    const user = await redis.get(userId);
    if (user === "1") {
      // the user has already active session
      return getDefaultResponse(req, userId);
    } else {
      // capacity is full so the user is forwarded to waiting room
      return getWaitingRoomResponse();
    }
  }
}

function makeid(length: number) {
  let result = "";
  const characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  const charactersLength = characters.length;
  for (let i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
}

async function getDefaultResponse(request: NextRequest, userId: string) {
  // uncomment below to test the function with a static html content
  let newResponse = new NextResponse(default_html);
  newResponse.headers.set("content-type", "text/html;charset=UTF-8");

  // const response = await fetch(request)
  // const newResponse = new Response(response.body, response)

  const cookies = request.cookies;
  const now = Date.now();
  let lastUpdate = cookies[COOKIE_NAME_TIME];
  let lastUpdateTime = 0;
  if (lastUpdate) lastUpdateTime = parseInt(lastUpdate);
  const diff = now - lastUpdateTime;
  const updateInterval = (SESSION_DURATION_SECONDS * 1000) / 2;
  if (diff > updateInterval) {
    await redis.setex(userId, SESSION_DURATION_SECONDS, "1");
    newResponse.cookie(COOKIE_NAME_TIME, now.toString());
  }
  newResponse.cookie(COOKIE_NAME_ID, userId);
  return newResponse;
}

async function getWaitingRoomResponse() {
  const newResponse = new NextResponse(waiting_room_html);
  newResponse.headers.set("content-type", "text/html;charset=UTF-8");
  return newResponse;
}

const waiting_room_html = `
<title>Waiting Room</title>
<meta http-equiv='refresh' content='30' />

<style>*{box-sizing:border-box;margin:0;padding:0}body{line-height:1.4;font-size:1rem;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif;padding:2rem;display:grid;place-items:center;min-height:100vh}.container{width:100%;max-width:800px}p{margin-top:.5rem}</style>

<div class='container'>
 <h1>
   <div>You are now in line.</div>
   <div>Thanks for your patience.</div>
 </h1>
 <p>We are experiencing a high volume of traffic. Please sit tight and we will let you in soon. </p>
 <p><b>This page will automatically refresh, please do not close your browser.</b></p>
</div>
`;

const default_html = `
<title>Waiting Room Demo</title>

<style>*{box-sizing:border-box;margin:0;padding:0}body{line-height:1.4;font-size:1rem;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif;padding:2rem;display:grid;place-items:center;min-height:100vh}.container{width:100%;max-width:800px}p{margin-top:.5rem}</style>

<div class="container">
 <h1>
   <div>Waiting Room Demo</div>
 </h1>
   <p>
             Visit this site from a different browser, you will be forwarded to the waiting room when the capacity is full.
   </p>
 <p>  Check <a href='//github.com/upstash/redis-examples/tree/master/nextjs-waiting-room' style={{"color": "blue"}}>this project </a> to set up a waiting room for your website.</p>
</div>
`;

Chúng tôi sử dụng Upstash Redis làm kho lưu trữ trạng thái để giữ các phiên hoạt động của người dùng. Nhờ API REST của nó, Upash-redis tương thích với các chức năng của Vercel Edge.

Bạn cần tạo cơ sở dữ liệu Toàn cầu từ bảng điều khiển Upstash. Sao chép và dán mã thông báo REST và URL REST từ bảng điều khiển. Cơ sở dữ liệu Redis phải trống và chỉ được sử dụng bởi ứng dụng này.

Đồng thời đặt TOTAL_ACTIVE_USERS và SESSION_DURATION_SECONDS tùy thuộc vào yêu cầu của riêng bạn.

Ứng dụng tạo một id duy nhất cho khách truy cập mới và đặt nó làm cookie và đẩy nó đến Redis. Vì vậy, trong lần tiếp theo, ứng dụng sẽ kiểm tra xem khách truy cập đã có phiên kiểm tra Redis chưa. Trong khi chèn vào Redis, nó đặt thời gian hết hạn là thời gian chờ phiên không hoạt động. Nếu số lượng phiên vượt quá công suất tối đa, người dùng mới sẽ được chuyển tiếp đến trang phòng chờ.

Bạn có thể cập nhật waiting_room_html để tùy chỉnh trang phòng chờ.

Bạn có thể cập nhật getDefaultResponse() để chuyển tiếp đến trang của riêng bạn bằng NextResponse.

Bước 3:Chạy và Triển khai

Chạy ứng dụng cục bộ bằng cách npm run dev . Bạn có thể muốn đặt 1 thành TOTAL_ACTIVE_USERS và mở trang (https:// localhost:3000 / api / hello) trong các trình duyệt khác nhau để dễ dàng kiểm tra phòng chờ.

Bạn có thể triển khai ứng dụng của mình cho Vercel bằng

vercel deploy –prod

Vercel sẽ chạy _middleware.ts ở các vị trí cạnh để giảm thiểu độ trễ trên toàn cầu.

Kết luận

Hướng dẫn này cho thấy việc xây dựng một ứng dụng động dễ dàng như thế nào nhờ Vercel và Upstash. Kiểm tra các ví dụ của chúng tôi để biết thêm các ví dụ khác.

Đang chờ phản hồi của bạn trên Twitter hoặc Discord.