Čeština

Prozkoumejte pokročilé techniky úpravy požadavků pomocí middleware Next.js. Naučte se zvládat složité směrování, ověřování, A/B testování a lokalizační strategie pro robustní webové aplikace.

Okrajové případy middleware Next.js: Zvládnutí vzorců úprav požadavků

Middleware Next.js poskytuje výkonný mechanismus pro zachycování a úpravu požadavků ještě předtím, než se dostanou k trasám vaší aplikace. Tato schopnost otevírá širokou škálu možností, od jednoduchých kontrol ověřování až po komplexní scénáře A/B testování a internacionalizační strategie. Nicméně efektivní využití middleware vyžaduje hluboké pochopení jeho okrajových případů a potenciálních úskalí. Tato komplexní příručka zkoumá pokročilé vzorce úprav požadavků a poskytuje praktické příklady a použitelné poznatky, které vám pomohou vytvořit robustní a výkonné aplikace Next.js.

Pochopení základů middleware Next.js

Než se ponoříme do pokročilých vzorců, zrekapitulujme si základy middleware Next.js. Funkce middleware se provádějí před dokončením požadavku, což vám umožňuje:

Funkce middleware se nacházejí v souboru middleware.js nebo middleware.ts v adresáři /pages nebo /app (v závislosti na vaší verzi a nastavení Next.js). Obdrží objekt NextRequest reprezentující příchozí požadavek a mohou vrátit objekt NextResponse pro řízení následného chování.

Příklad: Základní ověřovací middleware

Tento příklad demonstruje jednoduchou kontrolu ověřování. Pokud uživatel není ověřen (např. v souboru cookie není platný token), je přesměrován na přihlašovací stránku.


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const authToken = request.cookies.get('authToken')

  if (!authToken) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/protected/:path*'],
}

Tento middleware se spustí pouze pro trasy, které odpovídají /protected/:path*. Kontroluje přítomnost souboru cookie authToken. Pokud soubor cookie chybí, je uživatel přesměrován na stránku /login. V opačném případě je požadavek povolen a pokračuje normálně pomocí NextResponse.next().

Pokročilé vzorce úprav požadavků

Nyní se podívejme na některé pokročilé vzorce úprav požadavků, které ukazují skutečnou sílu middleware Next.js.

1. A/B testování se soubory cookie

A/B testování je klíčová technika pro optimalizaci uživatelských zkušeností. Middleware lze použít k náhodnému přiřazení uživatelů k různým variantám vaší aplikace a sledování jejich chování. Tento vzorec se spoléhá na soubory cookie pro zachování přiřazené varianty uživatele.

Příklad: A/B testování vstupní stránky


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const VARIANT_A = 'variantA'
const VARIANT_B = 'variantB'

export function middleware(request: NextRequest) {
  let variant = request.cookies.get('variant')?.value

  if (!variant) {
    // Náhodně přiřadí variantu
    variant = Math.random() < 0.5 ? VARIANT_A : VARIANT_B
    const response = NextResponse.next()
    response.cookies.set('variant', variant)
    return response
  }

  if (variant === VARIANT_A) {
    return NextResponse.rewrite(new URL('/variant-a', request.url))
  } else if (variant === VARIANT_B) {
    return NextResponse.rewrite(new URL('/variant-b', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/'],
}

V tomto příkladu, když uživatel poprvé navštíví kořenovou cestu (/), middleware jim náhodně přiřadí buď variantA, nebo variantB. Tato varianta je uložena v souboru cookie. Následné požadavky od stejného uživatele budou přepsány na /variant-a nebo /variant-b v závislosti na jejich přiřazené variantě. To vám umožní obsluhovat různé vstupní stránky a sledovat, která z nich má lepší výkon. Ujistěte se, že máte definované trasy pro /variant-a a /variant-b ve vaší aplikaci Next.js.

Globální úvahy: Při provádění A/B testování zvažte regionální rozdíly. Design, který rezonuje v Severní Americe, nemusí být v Asii tak efektivní. Pro přizpůsobení A/B testu konkrétním regionům můžete použít data o geografické poloze (získaná prostřednictvím vyhledávání IP adresy nebo preferencí uživatelů).

2. Lokalizace (i18n) s přepsáním adres URL

Internacionalizace (i18n) je nezbytná pro oslovení globálního publika. Middleware lze použít k automatické detekci preferovaného jazyka uživatele a přesměrování na příslušnou lokalizovanou verzi vašeho webu.

Příklad: Přesměrování na základě hlavičky `Accept-Language`


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const SUPPORTED_LANGUAGES = ['en', 'fr', 'es', 'de']
const DEFAULT_LANGUAGE = 'en'

function getPreferredLanguage(request: NextRequest): string {
  const acceptLanguage = request.headers.get('accept-language')
  if (!acceptLanguage) {
    return DEFAULT_LANGUAGE
  }

  const languages = acceptLanguage.split(',').map((lang) => lang.split(';')[0].trim())

  for (const lang of languages) {
    if (SUPPORTED_LANGUAGES.includes(lang)) {
      return lang
    }
  }

  return DEFAULT_LANGUAGE
}

export function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname

  // Zkontrolujte, zda v cestě existuje existující národní prostředí
  if (
    SUPPORTED_LANGUAGES.some(
      (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
    )
  ) {
    return NextResponse.next()
  }

  const preferredLanguage = getPreferredLanguage(request)

  return NextResponse.redirect(
    new URL(`/${preferredLanguage}${pathname}`, request.url)
  )
}

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)
  ],
}

Tento middleware extrahuje hlavičku Accept-Language z požadavku a určí preferovaný jazyk uživatele. Pokud adresa URL ještě neobsahuje předponu jazyka (např. /en/about), middleware přesměruje uživatele na příslušnou lokalizovanou adresu URL (např. /fr/about pro francouzštinu). Ujistěte se, že máte ve svém adresáři `/pages` nebo `/app` správnou strukturu složek pro různé národní prostředí. Například budete potřebovat soubory `/pages/en/about.js` a `/pages/fr/about.js`.

Globální úvahy: Ujistěte se, že vaše implementace i18n správně zpracovává jazyky psané zprava doleva (např. arabština, hebrejština). Zvažte také použití sítě pro doručování obsahu (CDN) k obsluhování lokalizovaných aktiv ze serverů blíže k vašim uživatelům, což zlepší výkon.

3. Feature Flags

Feature flags vám umožňují povolit nebo zakázat funkce ve vaší aplikaci, aniž byste nasazovali nový kód. To je zvláště užitečné pro postupné zavádění nových funkcí nebo pro testování funkcí v produkci. Middleware lze použít ke kontrole stavu feature flag a odpovídající úpravě požadavku.

Příklad: Povolení beta funkce


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const BETA_FEATURE_ENABLED = process.env.BETA_FEATURE_ENABLED === 'true'

export function middleware(request: NextRequest) {
  if (BETA_FEATURE_ENABLED && request.nextUrl.pathname.startsWith('/new-feature')) {
    return NextResponse.next()
  }

  // Volitelně přesměrovat na stránku „funkce není k dispozici“
  return NextResponse.rewrite(new URL('/feature-unavailable', request.url))
}

export const config = {
  matcher: ['/new-feature/:path*'],
}

Tento middleware kontroluje hodnotu proměnné prostředí BETA_FEATURE_ENABLED. Pokud je nastavena na true a uživatel se snaží přistoupit k trase v části /new-feature, je požadavek povolen a pokračuje. V opačném případě je uživatel přesměrován na stránku /feature-unavailable. Nezapomeňte správně konfigurovat proměnné prostředí pro různá prostředí (vývoj, staging, produkce).

Globální úvahy: Při používání feature flags zvažte právní důsledky povolení funkcí, které nemusí být v souladu s předpisy ve všech regionech. Například funkce související s ochranou osobních údajů možná bude nutné v určitých zemích zakázat.

4. Detekce zařízení a adaptivní směrování

Moderní webové aplikace musí být responzivní a přizpůsobit se různým velikostem obrazovky a možnostem zařízení. Middleware lze použít k detekci typu zařízení uživatele a přesměrování na optimalizované verze vašeho webu.

Příklad: Přesměrování mobilních uživatelů na mobilní subdoménu


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { device } from 'detection'

export function middleware(request: NextRequest) {
  const userAgent = request.headers.get('user-agent')

  if (userAgent) {
    const deviceType = device(userAgent)

    if (deviceType.type === 'phone') {
      const mobileUrl = new URL(request.url)
      mobileUrl.hostname = 'm.example.com'
      return NextResponse.redirect(mobileUrl)
    }
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/'],
}

Tento příklad používá knihovnu `detection` k určení typu zařízení uživatele na základě hlavičky User-Agent. Pokud je uživatel na mobilním telefonu, je přesměrován na subdoménu m.example.com (za předpokladu, že tam máte hostovanou mobilně optimalizovanou verzi svého webu). Nezapomeňte nainstalovat balíček `detection`: `npm install detection`.

Globální úvahy: Ujistěte se, že vaše logika detekce zařízení zohledňuje regionální variace v používání zařízení. Například v některých rozvojových zemích jsou stále rozšířené běžné telefony. Zvažte použití kombinace detekce User-Agent a technik responzivního designu pro robustnější řešení.

5. Obohacení hlavičky požadavku

Middleware může přidat informace do hlaviček požadavku před tím, než je zpracují trasy vaší aplikace. To je užitečné pro přidání vlastních metadat, jako jsou role uživatelů, stav ověřování nebo ID požadavku, které mohou být použity logikou vaší aplikace.

Příklad: Přidání ID požadavku


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { v4 as uuidv4 } from 'uuid'

export function middleware(request: NextRequest) {
  const requestId = uuidv4()
  const response = NextResponse.next()
  response.headers.set('x-request-id', requestId)
  return response
}

export const config = {
  matcher: ['/api/:path*'], // Pouze pro API trasy
}

Tento middleware generuje jedinečné ID požadavku pomocí knihovny uuid a přidává ho do hlavičky x-request-id. Toto ID lze poté použít pro protokolování, trasování a účely ladění. Nezapomeňte nainstalovat balíček uuid: npm install uuid.

Globální úvahy: Při přidávání vlastních hlaviček mějte na paměti limity velikosti hlaviček. Překročení těchto limitů může vést k neočekávaným chybám. Ujistěte se také, že jsou veškeré citlivé informace přidané do hlaviček řádně chráněny, zejména pokud se vaše aplikace nachází za reverzním proxy nebo sítí CDN.

6. Zlepšení zabezpečení: Omezování rychlosti

Middleware může fungovat jako první linie obrany proti útokům tím, že implementuje omezování rychlosti. Tím se zabrání zneužití omezením počtu požadavků, které může klient provést v určitém časovém okně.

Příklad: Základní omezování rychlosti pomocí jednoduchého úložiště


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const requestCounts: { [ip: string]: number } = {}
const WINDOW_SIZE_MS = 60000; // 1 minuta
const MAX_REQUESTS_PER_WINDOW = 100;

export function middleware(request: NextRequest) {
  const clientIP = request.ip || '127.0.0.1' // Získat IP adresu klienta, výchozí hodnota localhost pro místní testování

  if (!requestCounts[clientIP]) {
    requestCounts[clientIP] = 0;
  }

  requestCounts[clientIP]++;

  if (requestCounts[clientIP] > MAX_REQUESTS_PER_WINDOW) {
    return new NextResponse(
      JSON.stringify({ message: 'Příliš mnoho požadavků' }),
      { status: 429, headers: { 'Content-Type': 'application/json' } }
    );
  }

  // Reset počítadla po okně
  setTimeout(() => {
    requestCounts[clientIP]--;
    if (requestCounts[clientIP] <= 0) {
        delete requestCounts[clientIP];
    }
  }, WINDOW_SIZE_MS);

  return NextResponse.next();
}

export const config = {
  matcher: ['/api/:path*'], // Použít pro všechny API trasy
}

Tento příklad udržuje jednoduché úložiště v paměti (requestCounts) pro sledování počtu požadavků od každé IP adresy. Pokud klient překročí MAX_REQUESTS_PER_WINDOW v rámci WINDOW_SIZE_MS, middleware vrátí chybu 429 Too Many Requests. Důležité: Toto je zjednodušený příklad a není vhodný pro produkční prostředí, protože se nerozšiřuje a je zranitelný vůči útokům typu odmítnutí služby. Pro použití v produkci zvažte použití robustnějšího řešení omezování rychlosti, jako je Redis nebo specializovaná služba omezování rychlosti.

Globální úvahy: Strategie omezování rychlosti by měly být přizpůsobeny konkrétním charakteristikám vaší aplikace a geografickému rozložení vašich uživatelů. Zvažte použití různých limitů rychlosti pro různé regiony nebo segmenty uživatelů.

Okrajové případy a potenciální úskalí

Zatímco middleware je výkonný nástroj, je nezbytné uvědomit si jeho omezení a potenciální úskalí:

Osvědčené postupy pro používání middleware Next.js

Chcete-li maximalizovat výhody middleware Next.js a vyhnout se potenciálním problémům, postupujte podle těchto osvědčených postupů:

Závěr

Middleware Next.js nabízí výkonný způsob, jak upravovat požadavky a přizpůsobovat chování vaší aplikace na okraji sítě. Pochopením pokročilých vzorců úprav požadavků diskutovaných v této příručce můžete vytvářet robustní, výkonné a globálně uvědomělé aplikace Next.js. Nezapomeňte pečlivě zvážit okrajové případy a potenciální úskalí a dodržovat osvědčené postupy uvedené výše, abyste zajistili, že vaše funkce middleware budou spolehlivé a udržovatelné. Osvojte si sílu middleware a vytvořte výjimečné uživatelské prostředí a odemkněte nové možnosti pro vaše webové aplikace.