Next.js 16 Middleware 2026: Edge Runtime, Xác thực và Câu hỏi Phỏng vấn
Hướng dẫn toàn diện về Next.js 16 Middleware trong năm 2026. Tìm hiểu cách Edge Runtime hoạt động, triển khai xác thực, path matching và chuẩn bị cho câu hỏi phỏng vấn frontend.

Next.js 16 Middleware chạy trước mỗi request đến server, trở thành tuyến phòng thủ đầu tiên cho xác thực, bản địa hóa và thao tác request. Hiểu về middleware là điều cần thiết để xây dựng ứng dụng production và là chủ đề thường xuất hiện trong các buổi phỏng vấn frontend.
Next.js 16 Middleware thực thi trong Edge Runtime theo mặc định, nghĩa là nó chạy tại các data center gần người dùng nhất với cold start dưới một mili giây. Điều này làm cho nó trở nên lý tưởng cho việc kiểm tra xác thực và redirect cần xảy ra trước khi trang được render.
Cách Next.js 16 Middleware Hoạt động
Middleware trong Next.js 16 chặn các request trước khi chúng đến route handler hoặc component trang. File middleware phải được đặt tại thư mục gốc của dự án (cùng cấp với app/ hoặc pages/) và export một hàm mặc định nhận đối tượng NextRequest.
Giới hạn của Edge Runtime có nghĩa là middleware không thể sử dụng các API Node.js như fs hoặc Buffer. Middleware chạy trên V8 isolates, tương tự như Cloudflare Workers, cho phép phân phối toàn cầu nhưng giới hạn các API khả dụng chỉ ở Web Standards.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Access request headers, cookies, and URL
const token = request.cookies.get('session')?.value
const pathname = request.nextUrl.pathname
// Log for debugging (visible in Vercel logs)
console.log(`Middleware: ${request.method} ${pathname}`)
// Continue to the route handler
return NextResponse.next()
}
// Configure which paths trigger middleware
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}Cấu hình matcher sử dụng cú pháp giống regex để định nghĩa các path nào sẽ kích hoạt middleware. Nếu không có cấu hình này, middleware sẽ chạy trên mọi request, bao gồm cả các tài nguyên tĩnh.
Mẫu Xác thực với Next.js Middleware
Middleware xuất sắc trong xác thực vì nó chạy trước khi bất kỳ code trang nào được thực thi. Người dùng không có phiên hợp lệ sẽ không bao giờ thấy nội dung được bảo vệ, dù chỉ thoáng qua. Điều này khác với kiểm tra auth phía client có thể hiển thị nội dung được bảo vệ trước khi redirect.
Mẫu sau đây xác thực token phiên và chuyển hướng người dùng chưa được xác thực. Nó tích hợp với bất kỳ nhà cung cấp auth nào lưu trữ dữ liệu phiên trong cookies hoặc headers.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const protectedPaths = ['/dashboard', '/settings', '/profile']
const authPaths = ['/login', '/signup']
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const sessionToken = request.cookies.get('session')?.value
// Check if path requires authentication
const isProtectedPath = protectedPaths.some(path =>
pathname.startsWith(path)
)
const isAuthPath = authPaths.some(path =>
pathname.startsWith(path)
)
// Validate session token (call auth service)
const isValidSession = sessionToken
? await validateSession(sessionToken)
: false
// Redirect unauthenticated users to login
if (isProtectedPath && !isValidSession) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('callbackUrl', pathname)
return NextResponse.redirect(loginUrl)
}
// Redirect authenticated users away from auth pages
if (isAuthPath && isValidSession) {
return NextResponse.redirect(new URL('/dashboard', request.url))
}
return NextResponse.next()
}
async function validateSession(token: string): Promise<boolean> {
// Call auth API endpoint or decode JWT
// Edge-compatible: use fetch, not Node.js crypto
try {
const response = await fetch('https://api.example.com/validate', {
headers: { Authorization: `Bearer ${token}` },
})
return response.ok
} catch {
return false
}
}Tham số callbackUrl lưu giữ đích đến ban đầu, để người dùng sẽ đến trang họ yêu cầu ban đầu sau khi đăng nhập.
Path Matching và Cấu hình Matcher
Cấu hình matcher xác định request nào sẽ kích hoạt middleware. Cấu hình sai có thể dẫn đến vấn đề hiệu suất (middleware chạy trên mọi tài nguyên tĩnh) hoặc lỗ hổng bảo mật (các path được bảo vệ không kích hoạt kiểm tra auth).
Next.js 16 hỗ trợ ba cú pháp matcher: đường dẫn string đơn giản, mẫu path với tham số, và mẫu giống regex với negative lookahead.
// Option 1: Simple string paths
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*'],
}
// Option 2: Exclude static assets with negative lookahead
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|public/).*)'],
}
// Option 3: Conditional matching with has/missing
export const config = {
matcher: [
{
source: '/api/:path*',
has: [{ type: 'header', key: 'Authorization' }],
},
{
source: '/dashboard/:path*',
missing: [{ type: 'cookie', key: 'session' }],
},
],
}Điều kiện has và missing trong tùy chọn 3 thêm logic trước khi middleware chạy. Điều này hiệu quả hơn việc kiểm tra bên trong hàm middleware.
Sẵn sàng chinh phục phỏng vấn React / Next.js?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Thao tác Request và Response trong Middleware
Ngoài xác thực, middleware có thể sửa đổi request trước khi đến route handler và response trước khi đến client. Các trường hợp sử dụng phổ biến bao gồm thêm security headers, viết lại URL cho A/B testing, và chèn dữ liệu geolocation.
Lớp NextResponse cung cấp các phương thức cho mỗi loại sửa đổi. Rewrite thay đổi đích đến mà không thay đổi URL trình duyệt, trong khi redirect cập nhật cả hai.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
// Add security headers to all responses
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set(
'Referrer-Policy',
'strict-origin-when-cross-origin'
)
// Inject geolocation into request headers for route handlers
const geo = request.geo
if (geo?.country) {
response.headers.set('x-user-country', geo.country)
response.headers.set('x-user-city', geo.city ?? 'unknown')
}
return response
}Dữ liệu geolocation (request.geo) được điền bởi Vercel Edge Network. Các triển khai tự host cần cấu hình điều này thông qua nhà cung cấp hosting hoặc sử dụng dịch vụ geolocation IP của bên thứ ba.
URL Rewriting cho A/B Testing và Feature Flags
Middleware rewrite cho phép phục vụ các trang khác nhau dựa trên cookies, headers, hoặc phân bổ ngẫu nhiên mà client không biết. Mẫu này hỗ trợ các framework A/B testing và triển khai tính năng dần dần.
Rewrite xảy ra tại edge, nên cả hai biến thể đều có cùng URL và được hưởng lợi từ edge caching khi phù hợp.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
// Check for existing variant assignment
let variant = request.cookies.get('ab-variant')?.value
// Assign variant if not set (50/50 split)
if (!variant && pathname === '/pricing') {
variant = Math.random() < 0.5 ? 'control' : 'treatment'
const response = NextResponse.rewrite(
new URL(`/pricing/${variant}`, request.url)
)
response.cookies.set('ab-variant', variant, {
maxAge: 60 * 60 * 24 * 30, // 30 days
httpOnly: true,
})
return response
}
// Rewrite to assigned variant
if (variant && pathname === '/pricing') {
return NextResponse.rewrite(
new URL(`/pricing/${variant}`, request.url)
)
}
return NextResponse.next()
}Cookie duy trì việc phân bổ biến thể, đảm bảo người dùng thấy cùng phiên bản khi quay lại. Thời hạn 30 ngày cân bằng giữa tính nhất quán của thử nghiệm và khả năng phân bổ lại người dùng vào các thử nghiệm mới.
Giới hạn Edge Runtime và Cách Khắc phục
Edge Runtime đánh đổi khả năng tương thích Node.js để có phân phối toàn cầu và cold start nhanh. Middleware không thể import các module đặc thù của Node.js, ảnh hưởng đến các thư viện như bcrypt, jsonwebtoken (khi sử dụng RS256), và các client database dựa trên socket TCP.
Tài liệu Edge Runtime của Next.js liệt kê các API được hỗ trợ. Web Crypto, fetch, và hầu hết Web Platform APIs hoạt động. Các tính toán nặng nên được chuyển sang API routes chạy trong Node.js.
import { jwtVerify } from 'jose' // Edge-compatible JWT library
import type { NextRequest } from 'next/server'
const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET!)
export async function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value
if (!token) {
return redirectToLogin(request)
}
try {
// jose library works in Edge Runtime
const { payload } = await jwtVerify(token, JWT_SECRET)
// Token is valid, check expiration
if (payload.exp && payload.exp < Date.now() / 1000) {
return redirectToLogin(request)
}
return NextResponse.next()
} catch {
// Invalid token signature or format
return redirectToLogin(request)
}
}
function redirectToLogin(request: NextRequest) {
const url = new URL('/login', request.url)
url.searchParams.set('callbackUrl', request.nextUrl.pathname)
return NextResponse.redirect(url)
}Thư viện jose cung cấp các thao tác JWT tương thích với Edge. Nó sử dụng Web Crypto bên trong, tránh module crypto của Node.js.
Câu hỏi Phỏng vấn Thường gặp về Next.js Middleware
Người phỏng vấn hỏi về middleware để đánh giá sự hiểu biết về vòng đời request, mẫu bảo mật, và các ràng buộc Edge computing. Những câu hỏi này xuất hiện trong các vị trí frontend và fullstack cấp cao làm việc với Next.js.
Middleware thực thi ở đâu trong vòng đời request?
Middleware chạy sau khi request đến server Next.js nhưng trước khi route matching hoặc render trang. Trên Vercel, nó thực thi tại Edge, nghĩa là data center gần nhất với người dùng. Vị trí này làm cho nó lý tưởng cho xác thực và redirect vì các request không hợp lệ không bao giờ đến server gốc.
Middleware không thể làm gì so với API routes?
Middleware chạy trong Edge Runtime, không phải Node.js. Nó không thể sử dụng các module tích hợp Node.js (fs, path, crypto với một số thuật toán nhất định), client database dựa trên TCP, hoặc các gói npm phụ thuộc vào API Node.js. Tính toán nặng nên được thực hiện trong API routes hoặc Server Components.
Làm thế nào để xử lý xác thực trong middleware mà không blocking?
Mẫu bao gồm kiểm tra cookie phiên, xác thực nó với endpoint auth hoặc bằng cách xác minh chữ ký JWT, và redirect nếu không hợp lệ. Để tránh blocking mọi request, sử dụng cấu hình matcher để chỉ chạy middleware trên các path được bảo vệ. Xác thực JWT stateless nhanh hơn việc gọi dịch vụ auth bên ngoài trên mọi request.
Điều gì xảy ra nếu middleware ném lỗi?
Lỗi không được xử lý trong middleware trả về response 500 cho client. Trang không bao giờ được render. Bọc logic middleware trong try-catch và trả về response dự phòng (thường là NextResponse.next()) ngăn chặn lỗi request hoàn toàn. Ghi log lỗi trước khi tiếp tục giúp việc debug.
Để thực hành sâu hơn với các khái niệm này, module câu hỏi phỏng vấn Next.js Middleware và Auth bao gồm các tình huống bổ sung.
Debug Middleware trong Development và Production
Các lỗi middleware khó theo dõi vì code chạy tại edge, không phải trong browser DevTools. Chế độ development hiển thị log middleware trong terminal, nhưng production yêu cầu cơ sở hạ tầng logging phù hợp.
Cách tiếp cận sau ghi log việc thực thi middleware với đủ ngữ cảnh để debug mà không lộ dữ liệu nhạy cảm.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const start = Date.now()
const requestId = crypto.randomUUID()
// Log request start
console.log(JSON.stringify({
type: 'middleware_request',
requestId,
method: request.method,
path: request.nextUrl.pathname,
userAgent: request.headers.get('user-agent')?.slice(0, 100),
country: request.geo?.country,
}))
// Process request
const response = processRequest(request)
// Log completion
console.log(JSON.stringify({
type: 'middleware_response',
requestId,
duration: Date.now() - start,
status: response.status,
}))
// Pass request ID to route handlers
response.headers.set('x-request-id', requestId)
return response
}
function processRequest(request: NextRequest): NextResponse {
// Middleware logic here
return NextResponse.next()
}Trên Vercel, các log này xuất hiện trong tab Functions. Các triển khai tự host nên gửi log đến dịch vụ như Datadog hoặc sử dụng structured logging mà nền tảng hosting có thể xử lý.
Best Practices Hiệu suất Middleware
Middleware chạy trên mọi request khớp. Một hàm middleware chậm sẽ thêm độ trễ vào mỗi lần tải trang. Mục tiêu là hoàn thành việc thực thi middleware trong dưới 5ms cho hầu hết các request.
- Giảm thiểu các thao tác async: Mỗi
awaitthêm độ trễ. Cache kết quả xác thực khi có thể. - Sử dụng cấu hình matcher: Loại trừ các tài nguyên tĩnh và path công khai không cần logic middleware.
- Tránh gọi bên ngoài trên mọi request: Xác thực JWT cục bộ thay vì gọi dịch vụ auth. Cache kết quả trong cookies khi phù hợp.
- Giữ kích thước bundle nhỏ: Middleware có giới hạn kích thước bundle riêng (1MB trên Vercel). Chỉ import những gì cần thiết.
Trang công nghệ React Next.js tại /technologies/react-next bao gồm các khái niệm liên quan như Server Components và mẫu data fetching bổ sung cho kiến thức middleware.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Checklist Next.js 16 Middleware cho Production
- Đặt middleware tại thư mục gốc dự án dưới tên
middleware.ts, không phải bên trongapp/hoặcpages/ - Cấu hình
matcherđể loại trừ_next/static,_next/image, và tài nguyên công khai khỏi việc thực thi middleware - Sử dụng các thư viện tương thích Edge cho xác thực JWT, như
josethay vìjsonwebtoken - Lưu callback URL trong tham số query khi redirect đến login, để người dùng quay lại đích đến dự định
- Thêm security headers trong middleware để áp dụng nhất quán trên tất cả các route
- Log việc thực thi middleware với request ID để theo dõi request qua hệ thống
- Giữ các cuộc gọi API bên ngoài ở mức tối thiểu bằng cách xác thực token cục bộ và lưu dữ liệu người dùng trong signed cookies
Bạn có tìm ra lỗi trong React / Next.js không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 20 tháng 9, 2026
Thẻ
Chia sẻ
Bài viết liên quan

Next.js 16 Cache Components năm 2026: use cache, PPR và Câu hỏi Phỏng vấn
Phân tích chuyên sâu về Next.js 16 Cache Components: directive use cache, Partial Pre-Rendering (PPR), cacheLife, cacheTag, và câu hỏi phỏng vấn thực tế cho developer senior.

React Compiler 2026: Tự động Memoization và Câu hỏi Phỏng vấn
Tìm hiểu React Compiler với tự động memoization, pipeline biên dịch HIR, các quy tắc React và câu hỏi phỏng vấn thường gặp năm 2026.

React 19 Suspense và Concurrent Rendering: Streaming SSR cùng Câu hỏi Phỏng vấn 2026
Hướng dẫn toàn diện về React 19 Suspense, concurrent rendering và streaming SSR. Bao gồm các ví dụ code thực tế và câu hỏi phỏng vấn thường gặp năm 2026.