Svenska

Utforska Next.js middleware, en kraftfull funktion för att avlyssna och modifiera inkommande förfrågningar. Lär dig hur du implementerar autentisering, auktorisering, omdirigering och A/B-testning med praktiska exempel.

Next.js Middleware: Bemästra avlyssning av förfrågningar för dynamiska applikationer

Next.js middleware erbjuder ett flexibelt och kraftfullt sätt att avlyssna och modifiera inkommande förfrågningar innan de når dina rutter. Denna förmåga gör att du kan implementera ett brett spektrum av funktioner, från autentisering och auktorisering till omdirigering och A/B-testning, allt medan du optimerar prestandan. Denna omfattande guide går igenom kärnkoncepten i Next.js middleware och visar hur du kan utnyttja det effektivt.

Vad är Next.js Middleware?

Middleware i Next.js är en funktion som körs innan en förfrågan slutförs. Det låter dig:

Middleware-funktioner definieras i filen middleware.ts (eller middleware.js) i roten av ditt projekt. De exekveras för varje rutt i din applikation, eller för specifika rutter baserat på konfigurerbara matchers.

Nyckelkoncept och fördelar

Request-objektet

request-objektet ger tillgång till information om den inkommande förfrågan, inklusive:

Response-objektet

Middleware-funktioner returnerar ett Response-objekt för att styra resultatet av förfrågan. Du kan använda följande responser:

Matchers

Matchers låter dig specificera vilka rutter din middleware ska tillämpas på. Du kan definiera matchers med hjälp av reguljära uttryck eller sökvägsmönster. Detta säkerställer att din middleware endast körs när det är nödvändigt, vilket förbättrar prestandan och minskar overhead.

Edge Runtime

Next.js middleware körs på Edge Runtime, vilket är en lättviktig JavaScript-körtidsmiljö som kan distribueras nära dina användare. Denna närhet minimerar latens och förbättrar den övergripande prestandan för din applikation, särskilt för globalt distribuerade användare. Edge Runtime är tillgänglig på Vercels Edge Network och andra kompatibla plattformar. Edge Runtime har vissa begränsningar, specifikt användningen av Node.js API:er.

Praktiska exempel: Implementera Middleware-funktioner

1. Autentisering

Autentiserings-middleware kan användas för att skydda rutter som kräver att användare är inloggade. Här är ett exempel på hur man implementerar autentisering med hjälp av cookies:


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

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

 return NextResponse.next()
}

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

Denna middleware kontrollerar förekomsten av en auth_token-cookie. Om cookien inte hittas omdirigeras användaren till sidan /login. config.matcher specificerar att denna middleware endast ska köras för rutter under /dashboard.

Globalt perspektiv: Anpassa autentiseringslogiken för att stödja olika autentiseringsmetoder (t.ex. OAuth, JWT) och integrera med olika identitetsleverantörer (t.ex. Google, Facebook, Azure AD) för att tillgodose användare från olika regioner.

2. Auktorisering

Auktoriserings-middleware kan användas för att kontrollera åtkomst till resurser baserat på användarroller eller behörigheter. Du kan till exempel ha en administratörspanel som endast specifika användare har åtkomst till.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

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

 // Example: Fetch user roles from an API (replace with your actual logic)
 const userResponse = await fetch('https://api.example.com/userinfo', {
 headers: {
 Authorization: `Bearer ${token}`,
 },
 });
 const userData = await userResponse.json();

 if (userData.role !== 'admin') {
 return NextResponse.redirect(new URL('/unauthorized', request.url))
 }

 return NextResponse.next()
}

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

Denna middleware hämtar användarens roll och kontrollerar om de har rollen admin. Om inte, omdirigeras de till en /unauthorized-sida. Detta exempel använder en platshållare för en API-slutpunkt. Ersätt `https://api.example.com/userinfo` med din faktiska slutpunkt för autentiseringsservern.

Globalt perspektiv: Var medveten om dataskyddsförordningar (t.ex. GDPR, CCPA) när du hanterar användardata. Implementera lämpliga säkerhetsåtgärder för att skydda känslig information och säkerställa efterlevnad av lokala lagar.

3. Omdirigering

Omdirigerings-middleware kan användas för att omdirigera användare baserat på deras plats, språk eller andra kriterier. Du kan till exempel omdirigera användare till en lokaliserad version av din webbplats baserat på deras IP-adress.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const country = request.geo?.country || 'US'; // Default to US if geo-location fails

 if (country === 'DE') {
 return NextResponse.redirect(new URL('/de', request.url))
 }

 if (country === 'FR') {
 return NextResponse.redirect(new URL('/fr', request.url))
 }

 return NextResponse.next()
}

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

Denna middleware kontrollerar användarens land baserat på deras IP-adress och omdirigerar dem till den lämpliga lokaliserade versionen av webbplatsen (/de för Tyskland, /fr för Frankrike). Om geolokaliseringen misslyckas, används den amerikanska versionen som standard. Notera att detta förlitar sig på att geo-egenskapen är tillgänglig (t.ex. vid driftsättning på Vercel).

Globalt perspektiv: Se till att din webbplats stöder flera språk och valutor. Ge användarna möjlighet att manuellt välja sitt föredragna språk eller region. Använd lämpliga datum- och tidsformat för varje locale.

4. A/B-testning

Middleware kan användas för att implementera A/B-testning genom att slumpmässigt tilldela användare till olika varianter av en sida och spåra deras beteende. Här är ett förenklat exempel:


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

function getRandomVariant() {
 return Math.random() < 0.5 ? 'A' : 'B';
}

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

 if (!variant) {
 variant = getRandomVariant();
 const response = NextResponse.next();
 response.cookies.set('variant', variant);
 return response;
 }

 if (variant === 'B') {
 return NextResponse.rewrite(new URL('/variant-b', request.url));
 }

 return NextResponse.next();
}

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

Denna middleware tilldelar användare antingen variant 'A' eller 'B'. Om en användare inte redan har en variant-cookie, tilldelas och sätts en slumpmässigt. Användare som tilldelas variant 'B' får sin förfrågan omskriven till sidan /variant-b. Du skulle sedan spåra prestandan för varje variant för att avgöra vilken som är mest effektiv.

Globalt perspektiv: Tänk på kulturella skillnader när du utformar A/B-tester. Det som fungerar bra i en region kanske inte tilltalar användare i en annan. Se till att din A/B-testningsplattform är förenlig med dataskyddsregler i olika regioner.

5. Funktionsflaggor

Funktionsflaggor (Feature flags) låter dig aktivera eller inaktivera funktioner i din applikation utan att behöva driftsätta ny kod. Middleware kan användas för att avgöra om en användare ska ha tillgång till en specifik funktion baserat på deras användar-ID, plats eller andra kriterier.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 // Example: Fetch feature flags from an API
 const featureFlagsResponse = await fetch('https://api.example.com/featureflags', {
 headers: {
 'X-User-Id': 'user123',
 },
 });
 const featureFlags = await featureFlagsResponse.json();

 if (featureFlags.new_feature_enabled) {
 // Enable the new feature
 return NextResponse.next();
 } else {
 // Disable the new feature (e.g., redirect to an alternative page)
 return NextResponse.redirect(new URL('/alternative-page', request.url));
 }
}

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

Denna middleware hämtar funktionsflaggor från ett API och kontrollerar om flaggan new_feature_enabled är satt. Om den är det kan användaren komma åt sidan /new-feature. Annars omdirigeras de till en /alternative-page.

Globalt perspektiv: Använd funktionsflaggor för att gradvis rulla ut nya funktioner till användare i olika regioner. Detta gör att du kan övervaka prestanda och åtgärda eventuella problem innan du släpper funktionen till en bredare publik. Se också till att ditt system för funktionsflaggor skalar globalt och ger konsekventa resultat oavsett användarens plats. Tänk på regionala regulatoriska begränsningar för funktionsutrullningar.

Avancerade tekniker

Kedjekoppling av Middleware

Du kan kedja ihop flera middleware-funktioner för att utföra en serie operationer på en förfrågan. Detta kan vara användbart för att bryta ner komplex logik i mindre, mer hanterbara moduler.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const response = NextResponse.next();

 // First middleware function
 const token = request.cookies.get('auth_token');
 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 // Second middleware function
 response.headers.set('x-middleware-custom', 'value');

 return response;
}

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

Detta exempel visar två middlewares i en. Den första utför autentisering och den andra sätter en anpassad header.

Använda miljövariabler

Lagra känslig information, som API-nycklar och databasuppgifter, i miljövariabler istället för att hårdkoda dem i dina middleware-funktioner. Detta förbättrar säkerheten och gör det enklare att hantera din applikations konfiguration.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const API_KEY = process.env.API_KEY;

export async function middleware(request: NextRequest) {
 const response = await fetch('https://api.example.com/data', {
 headers: {
 'X-API-Key': API_KEY,
 },
 });

 // ...
}

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

I detta exempel hämtas API_KEY från en miljövariabel.

Felhantering

Implementera robust felhantering i dina middleware-funktioner för att förhindra att oväntade fel kraschar din applikation. Använd try...catch-block för att fånga undantag och logga fel på lämpligt sätt.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 try {
 const response = await fetch('https://api.example.com/data');
 // ...
 } catch (error) {
 console.error('Error fetching data:', error);
 return NextResponse.error(); // Or redirect to an error page
 }
}

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

Bästa praxis

Felsökning av vanliga problem

Slutsats

Next.js middleware är ett kraftfullt verktyg för att bygga dynamiska och personliga webbapplikationer. Genom att bemästra avlyssning av förfrågningar kan du implementera ett brett spektrum av funktioner, från autentisering och auktorisering till omdirigering och A/B-testning. Genom att följa bästa praxis som beskrivs i denna guide kan du utnyttja Next.js middleware för att skapa högpresterande, säkra och skalbara applikationer som möter behoven hos din globala användarbas. Omfamna kraften i middleware för att låsa upp nya möjligheter i dina Next.js-projekt och leverera exceptionella användarupplevelser.