10 min read
ā¢Question 35 of 47hardAdvanced Middleware Patterns
Complex middleware implementations.
Advanced Middleware
Chained Middleware
code.txtTSX
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
// Middleware chain
const middlewares = [
authMiddleware,
rateLimitMiddleware,
localeMiddleware,
];
export async function middleware(request: NextRequest) {
let response = NextResponse.next();
for (const mw of middlewares) {
const result = await mw(request, response);
if (result instanceof NextResponse) {
response = result;
}
// Check if redirect or rewrite, break chain
if (response.headers.get('x-middleware-rewrite')) {
break;
}
}
return response;
}
async function authMiddleware(request: NextRequest, response: NextResponse) {
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return response;
}A/B Testing
code.txtTSX
export function middleware(request: NextRequest) {
const bucket = request.cookies.get('ab-bucket')?.value
|| (Math.random() < 0.5 ? 'a' : 'b');
const response = NextResponse.rewrite(
new URL(`/${bucket}${request.nextUrl.pathname}`, request.url)
);
if (!request.cookies.get('ab-bucket')) {
response.cookies.set('ab-bucket', bucket, { maxAge: 60 * 60 * 24 * 30 });
}
return response;
}Geolocation-Based Routing
code.txtTSX
export function middleware(request: NextRequest) {
const country = request.geo?.country || 'US';
const city = request.geo?.city || 'Unknown';
// Clone headers and add geo info
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-country', country);
requestHeaders.set('x-user-city', city);
// Redirect based on country
if (country === 'DE' && !request.nextUrl.pathname.startsWith('/de')) {
return NextResponse.redirect(new URL('/de' + request.nextUrl.pathname, request.url));
}
return NextResponse.next({
request: { headers: requestHeaders },
});
}