Next.js中间件:让页面代码变整洁的秘密武器
第一次听说Next.js中间件时,我心里想:"听起来不错,但真的有必要吗?"
现在我可以肯定地说:非常有必要。只要你做过用户权限验证、访问日志、A/B测试或者页面重定向中的任何一项,中间件就像是被低估的超强能力。
让我分享真正理解它价值的时刻,以及它如何把页面逻辑从混乱中拯救出来。
什么时候我真正体会到了它的好处?
那是在开发一个多角色应用时:管理员和普通用户需要不同的访问权限。每次用户访问受限制的页面,我不得不在页面或布局文件中加入:
用户权限验证
条件重定向逻辑
访问记录
偶尔还要做A/B测试
结果就是:代码变得臃肿,到处是重复的逻辑,if语句随处可见。换成中间件后,所有这些问题在一个文件中解决,入口统一了,页面代码也变得干净。
中间件到底是什么?
它在请求完成之前、在边缘运行你的代码,这是在react开始渲染之前就完成的。它像是一个轻量级的服务器功能。
中间件文件放在项目根目录,命名为middleware.ts(或者.js)。
看看这个基本例子:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
// 配置哪些路由需要经过中间件
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*'],
}这个简单的中间件就能保护指定路由,不需要修改任何页面文件。
我实际使用的场景
用户验证和重定向
未登录用户自动跳转到登录页
已登录用户不能访问登录页面
A/B测试
根据请求头或Cookie显示不同版本
保持用户始终看到同一个版本
多语言支持
根据用户地区跳转到对应语言站点
自动识别用户偏好语言
访问记录
记录用户访问路径和来源
统计会话信息
维护模式
在特定时间段屏蔽某些页面
显示维护提示页面
内部路由重写
把外部URL映射到内部页面
不改变浏览器地址栏的URL
路由匹配要精确
在middleware.ts中配置matcher,只对需要的页面生效,避免影响静态资源和公开页面。
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|public|api/public).*)',
],
}快速上手三步走
创建middleware.ts文件
写一个简单的权限检查:验证Cookie或Session,未登录就重定向
配置matcher:只保护需要验证的路由
完成这些,打开浏览器看看,页面逻辑立刻变得清晰整洁。
实用技巧
读取请求信息:使用request.nextUrl、request.headers、request.cookies
重写而不是跳转:用NextResponse.rewrite可以无刷新更换内容
设置Header和Cookie:通过response.headers.set和response.cookies.set
保持A/B测试一致性:第一次分配后写入Cookie,后续请求保持相同版本
注意运行环境:边缘运行时没有Node.js内置模块,避免重量级计算,尽量在10毫秒内完成
什么时候用?什么时候不用?
适合使用:
入口控制(权限、重定向、多语言、测试)
简单的访问记录
低延迟的路由重写
不适合使用:
需要访问数据库的复杂业务逻辑
这类需求更适合放在API路由或Server Actions中
为什么它如此有用?
页面代码更干净:把入口检查从组件中移走
跳转更快:在渲染前就决定页面去向
统一入口:所有入口规则在一个地方维护
不依赖额外服务:不需要自建后端服务器就能实现很多功能
完整示例:A/B测试 + 登录保护
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(req: NextRequest) {
const { nextUrl } = req
const res = NextResponse.next()
const token = req.cookies.get('token')?.value
const isProtected = nextUrl.pathname.startsWith('/app')
// 1. 登录保护
if (isProtected && !token) {
return NextResponse.redirect(new URL('/login', req.url))
}
// 2. A/B测试:如果没有Cookie就随机分配,然后设置Cookie保持一致性
let bucket = req.cookies.get('ab-home')?.value
if (!bucket) {
bucket = Math.random() < 0.5 ? 'A' : 'B'
res.cookies.set('ab-home', bucket, { path: '/', httpOnly: false })
}
// 3. 根据测试分组重写到不同页面
if (nextUrl.pathname === '/' && bucket === 'B') {
return NextResponse.rewrite(new URL('/home-b', req.url))
}
return res
}
export const config = {
matcher: ['/', '/app/:path*'],
}实际项目建议
从简单的需求开始,比如先实现登录保护。熟悉后再加入更复杂的功能。
注意错误处理,特别是在重定向时确保目标URL存在。
测试时要清除Cookie,确保中间件在各种情况下都能正常工作。
性能监控很重要,确保中间件不会成为瓶颈。
总结
把所有"入口需要做的事情"都集中到中间件中,页面和布局组件就能专注于内容展示。一个文件守护所有入口,这就是Next.js中间件的价值所在。
它让代码更易于维护,逻辑更清晰,开发效率更高。开始使用中间件,你会发现前端开发可以如此简洁高效。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!