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

エッジ関数を使用したNext.jsアプリの待合室

この投稿では、VercelEdge関数とUpstashRedisを使用してNext.jsアプリケーションの待合室を作成します。

ソースコードとデモアプリを確認できます。

待合室?

待合室は、リソースが過負荷にならないように、Webサイトへのアクティブな訪問者の数を制限したい場合に便利です。

私たちの実装では、アクティブな訪問者の最大数を設定することができます。トラフィックを制御するための2つのパラメータがあります:

  • ウェブサイトの最大容量:同時にウェブサイトにアクセスする最大数は?
  • 最大セッションタイムアウト:訪問者がアイドル状態を維持できる最大秒数

ステップ1:プロジェクトのセットアップ

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.

upstash-redisをインストールします:

npm install @upstash/redis

ステップ2:実装

Vercelは、Next.jsミドルウェアを介してEdge機能をサポートします。したがって、pages/api/の下に_middleware.tsを追加します 。ミドルウェアコードは、/apiに対して行われたすべてのリクエストをインターセプトします。さまざまな構成については、こちらをご覧ください。

pages/api/_middleware.tsを更新します 以下のように:

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>
`;

アクティブなユーザーセッションを維持するための状態ストアとしてUpstashRedisを使用します。そのRESTAPIのおかげで、upstash-redisはVercelEdge関数と互換性があります。

Upstashコンソールからグローバルデータベースを作成する必要があります。コンソールからRESTトークンとRESTURLをコピーして貼り付けます。 Redisデータベースは空であり、このアプリケーションでのみ使用する必要があります。

また、独自の要件に応じて、TOTAL_ACTIVE_USERSとSESSION_DURATION_SECONDSを設定します。

アプリケーションは、新規訪問者の一意のIDを作成し、それをCookieとして設定して、Redisにプッシュします。そのため、次回、アプリケーションは、訪問者がRedisをチェックするセッションをすでに持っているかどうかをチェックします。 Redisに挿入している間、有効期限をセッションアイドルタイムアウトとして設定します。セッション数が最大容量を超えると、新しいユーザーは待合室ページに転送されます。

waiting_room_htmlを更新できます 待合室のページをカスタマイズします。

getDefaultResponse()を更新できます NextResponseを使用して自分のページに転送する方法。

ステップ3:実行してデプロイ

npm run devによってアプリケーションをローカルで実行します 。 TOTAL_ACTIVE_USERSに1を設定することをお勧めします 待合室を簡単にテストするには、さまざまなブラウザでページ(http:// localhost:3000 / api / hello)を開きます。

によってアプリケーションをVercelにデプロイできます。

vercel deploy –prod

Vercelは、遅延をグローバルに最小化するために、エッジロケーションで_middleware.tsを実行します。

結論

このチュートリアルでは、VercelとUpstashのおかげで、エッジで動的アプリケーションを簡単に構築できることを紹介します。その他の例については、例を確認してください。

TwitterまたはDiscordでフィードバックを待っています。


  1. iOS 13 ダーク モード用にアプリを設定する方法

    Apple は、待望の iOS 13 アップデートを 9 月 19 日に、過去 4 年間 (iPhone 6s に遡る) 内に発売されたすべての iPhone でグローバルにリリースしました。 このアップデートの最大の機能の 1 つは、システム全体の iOS 13 ダーク モードでした。スマートフォンのディスプレイから放出される白色光によって引き起こされる眼精疲労に役立つことが期待されています. この機能は、Apple デバイスを使用する最終消費者にとっては喜ばしいことですが、iOS 開発者にとっては、iOS 13 ダーク モードに対応したアプリを準備する作業です。 iOS 13 ダーク

  2. CCleaner for Android のレビュー:電話を修理する

    スマートフォンは、私たちが他の人とつながることを可能にするだけでなく、私たちの財布、ガイド、娯楽、そして多くの人にとって仕事の源になっているため、私たちが持っている最も重要で価値のあるものです.新品のスマートフォンを手にしたときは誰もがワクワクしますが、数か月使用した後は同じようには感じません。素早いナビゲーション、時代を超越した応答、マイクロ秒のアプリ起動機能は消えてしまい、ラグの問題、アプリを開くための待ち時間の増加などに置き換えられたようです. いいえ、今はスマートフォンを買い替える時ではなく、最適化する時です。すべての機械にはメンテナンスが必要であり、スマートフォンも例外ではありませ