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:
- Přepsat adresy URL: Přesměrovat uživatele na různé stránky na základě konkrétních kritérií.
- Přesměrovat uživatele: Posílat uživatele na zcela odlišné adresy URL, často pro účely ověřování nebo autorizace.
- Upravit hlavičky: Přidávat, odebírat nebo aktualizovat hlavičky HTTP.
- Reagovat přímo: Vrátit odpověď přímo z middleware, čímž se obejdou trasy Next.js.
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í:
- Dopad na výkon: Middleware přidává režii do každého požadavku. Vyhněte se provádění výpočetně náročných operací v middleware, protože to může výrazně ovlivnit výkon. Profilujte svůj middleware, abyste identifikovali a optimalizovali případná úzká hrdla výkonu.
- Složitost: Nadměrné používání middleware může ztížit pochopení a údržbu vaší aplikace. Používejte middleware uvážlivě a ujistěte se, že každá funkce middleware má jasný a dobře definovaný účel.
- Testování: Testování middleware může být náročné, protože vyžaduje simulaci požadavků HTTP a kontrolu výsledných odpovědí. Použijte nástroje jako Jest a Supertest k zápisu komplexních jednotkových a integračních testů pro vaše funkce middleware.
- Správa souborů cookie: Buďte opatrní při nastavování souborů cookie v middleware, protože to může ovlivnit chování při ukládání do mezipaměti. Ujistěte se, že rozumíte důsledkům ukládání do mezipaměti na bázi souborů cookie a odpovídajícím způsobem nakonfigurujte hlavičky mezipaměti.
- Proměnné prostředí: Ujistěte se, že všechny proměnné prostředí použité ve vašem middleware jsou správně nakonfigurovány pro různá prostředí (vývoj, staging, produkce). Použijte nástroj jako Dotenv ke správě proměnných prostředí.
- Omezení okrajových funkcí: Pamatujte, že middleware běží jako okrajové funkce, které mají omezení doby provádění, využití paměti a velikosti svázaného kódu. Udržujte své funkce middleware lehké a efektivní.
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ů:
- Udržujte to jednoduché: Každá funkce middleware by měla mít jedinou, dobře definovanou odpovědnost. Vyhněte se vytváření příliš složitých funkcí middleware, které provádějí více úloh.
- Optimalizujte pro výkon: Minimalizujte množství zpracování prováděného v middleware, abyste se vyhnuli úzkým hrdlům výkonu. Použijte strategie ukládání do mezipaměti ke snížení potřeby opakovaných výpočtů.
- Důkladně testujte: Zapište komplexní jednotkové a integrační testy pro vaše funkce middleware, abyste zajistili, že se chovají podle očekávání.
- Dokumentujte svůj kód: Jasně dokumentujte účel a funkčnost každé funkce middleware pro zlepšení udržovatelnosti.
- Sledujte svou aplikaci: Použijte monitorovací nástroje ke sledování výkonu a chybovosti vašich funkcí middleware.
- Pochopte pořadí provádění: Uvědomte si pořadí, ve kterém jsou funkce middleware prováděny, protože to může ovlivnit jejich chování.
- Používejte proměnné prostředí moudře: Použijte proměnné prostředí ke konfiguraci funkcí middleware pro různá prostředí.
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.