You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js Middleware重定向未达预期 路由鉴权逻辑异常排查

Next.js Middleware 重定向失效修复方案

核心问题

原代码重定向逻辑不生效的核心原因有4个:

  • 直接用req.url做路由匹配:req.url是带协议、域名、端口的完整绝对地址,存在validRoutes里的是相对路径,字符串匹配永远无法命中
  • 逻辑分支冗余:if(url包含login路径)和else if(url不包含login路径)已经覆盖了所有可能场景,最后的else分支是永远走不到的死代码
  • 跳转/重写传参不规范:直接传相对路径给NextResponse.redirect/rewrite,在部分Next.js版本、非根域名部署场景下会解析失败
  • 没做路径规范化:带查询参数、尾斜杠的合法路径会被直接判定为非法路由,匹配逻辑鲁棒性差

修复后完整代码

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// 项目基础路径,适配basePath部署场景
const base_url = process.env.NEXT_PUBLIC_BASE_PATH || ''
// 无需登录即可访问的公开路由
const publicRoutes = [
  `${base_url}/login`,
  `${base_url}/404`,
  `${base_url}/api/auth/user`,
  `${base_url}/api/auth/logout`,
  `${base_url}/api/auth/setpass`
]
// 登录后可访问的受保护路由,后续可按角色拆分权限映射表
const protectedRoutes = [
  `${base_url}/`,
  // 补充业务侧受保护路由,比如`${base_url}/dashboard`、`${base_url}/user/profile`等
]
// 所有合法路由汇总,用于404判定
const allValidRoutes = [...publicRoutes, ...protectedRoutes]

export function middleware(req: NextRequest) {
  const { cookies, nextUrl } = req
  // 获取规范化的当前路径,自动剔除域名、查询参数、锚点
  const currentPath = nextUrl.pathname
  const jwt = cookies.get('user')?.value

  // 页面访问监控埋点位置,可在此处上报访问路径、用户token状态、UA等信息,支撑后续角色权限审计、行为分析
  // 示例:await fetch(`${base_url}/api/monitor/track`, { method: 'POST', body: JSON.stringify({ path: currentPath, hasToken: !!jwt, timestamp: Date.now() }) })

  // 场景1:已登录用户访问登录页,直接跳转首页
  if (currentPath === `${base_url}/login`) {
    if (jwt) return NextResponse.redirect(new URL(`${base_url}/`, req.url))
    return NextResponse.next()
  }

  // 路径合法性校验:不区分登录态,非法路径统一重写到404页
  const isRouteValid = allValidRoutes.some(route => {
    const normalizedRoute = route.endsWith('/') ? route.slice(0, -1) : route
    const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : currentPath
    return normalizedRoute === normalizedPath
  })
  if (!isRouteValid) {
    return NextResponse.rewrite(new URL(`${base_url}/404`, req.url))
  }

  // 公开路由直接放行
  const isPublicRoute = publicRoutes.some(route => {
    const normalizedRoute = route.endsWith('/') ? route.slice(0, -1) : route
    const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : currentPath
    return normalizedRoute === normalizedPath
  })
  if (isPublicRoute) return NextResponse.next()

  // 受保护路由登录态校验
  if (jwt) {
    // 角色权限扩展点:在此处解析jwt拿到用户角色,判断当前路径是否在该角色的可访问路由列表内,无权限可跳403页
    return NextResponse.next()
  }

  // 未登录访问受保护路由,拼接回跳参数后跳登录页
  const loginUrl = new URL(`${base_url}/login`, req.url)
  loginUrl.searchParams.set('redirect', currentPath)
  return NextResponse.redirect(loginUrl)
}

// 配置middleware生效范围,排除静态资源、Next.js内部路径,减少无效执行
export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
}

关键调整说明

  • 路由匹配统一用req.nextUrl.pathname获取纯路径,从根源解决完整URL和相对路径匹配失败的问题
  • 重构逻辑分层,按「登录页特殊处理→路由合法性校验→公开路由放行→登录态/权限校验」的顺序处理,没有死分支,逻辑可追溯
  • 所有跳转、重写操作统一用new URL(目标路径, req.url)生成标准URL对象,兼容各种部署场景,不会出现路径解析失败
  • 增加路径规范化逻辑,自动忽略路径尾斜杠差异,避免合法路径被误拦截
  • 预留了访问监控埋点、角色权限判断的扩展位置,直接在对应位置加业务代码即可支撑访问行为监控、角色权限管理的需求
  • 增加matcher配置,跳过静态资源等不需要鉴权的路径,提升middleware运行性能
  • 未登录跳转时自动携带原始访问路径参数,用户登录后可直接回跳到目标页,交互体验更好

内容的提问来源于stack exchange,提问作者Emmanuel Osei Mensah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 20:03:39