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

NextJS 13重定向后页面空白问题求助(API路由+中间件场景)

问题分析

你的核心问题出在两个关键环节:

  1. Middleware路由范围未做限制:当前Middleware会拦截所有请求(包括/login页面和api路由本身),导致/login页面的请求被强制转发到api/authUser,而该接口检测到请求路径是/login时直接返回空响应,最终页面显示空白。
  2. 错误使用rewrite而非直接处理校验/跳转:NextResponse.rewrite是服务器内部请求转发,会把目标路由的响应作为当前请求的返回内容。你需要的是未登录时的页面跳转,应该用redirect,或者直接在Middleware中完成校验逻辑,而非转发到API路由。
解决方案

方案1:在Middleware中直接完成登录校验(推荐)

Next.js 13的Middleware支持在边缘函数中直接调用外部接口,无需转发到内部API路由,逻辑更高效清晰。

修改src/middleware.ts:

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

export async function middleware(req: NextRequest) {
  // 定义需要校验的受保护路由
  const currentPath = req.nextUrl.pathname

  // 排除无需校验的路由:登录页、API路由、静态资源
  if (currentPath === '/login' || currentPath.startsWith('/api/') || currentPath.startsWith('/_next/')) {
    return NextResponse.next()
  }

  try {
    // 调用后端校验接口,传递原请求Cookie以识别用户状态
    const res = await fetch('http://localhost:8082/api/auth/user', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Cookie: req.headers.get('Cookie') || ''
      },
      credentials: 'include'
    })

    const data = await res.json()

    // 校验失败则重定向到登录页
    if (data.error) {
      return NextResponse.redirect(new URL('/login', req.url))
    }

    // 校验通过,正常放行
    return NextResponse.next()
  } catch (err) {
    // 接口调用异常时也重定向到登录页
    console.error('登录校验失败:', err)
    return NextResponse.redirect(new URL('/login', req.url))
  }
}

// 可选:指定Middleware生效的路由范围,缩小拦截范围
export const config = {
  matcher: ['/', '/dashboard/:path*'] // 替换为你的受保护路由
}

方案2:保留API路由但修复Middleware逻辑

如果坚持通过内部API路由处理校验,需调整Middleware避免拦截关键路由:

修改src/middleware.ts:

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

export function middleware(req: NextRequest) {
  const currentPath = req.nextUrl.pathname

  // 排除登录页、API路由、静态资源,避免循环拦截
  if (currentPath === '/login' || currentPath.startsWith('/api/') || currentPath.startsWith('/_next/')) {
    return NextResponse.next()
  }

  // 仅对受保护页面转发到校验接口
  return NextResponse.rewrite(new URL('/api/authUser', req.url))
}

同时修改api/authUser.ts,确保校验逻辑正确:

import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
  error?: string
  user?: any
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  try {
    const options = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Cookie: req.headers.cookie || ''
      },
      credentials: 'include'
    }

    const response = await fetch('http://localhost:8082/api/auth/user', options)
    const data = await response.json()

    if (data.error) {
      res.writeHead(302, { Location: '/login' })
      return res.end()
    }

    // 校验通过返回用户信息,或直接放行(此方案更适合方案1)
    res.status(200).json({ user: data })
  } catch (err) {
    res.writeHead(302, { Location: '/login' })
    res.end()
  }
}

export const config = {
  api: {
    externalResolver: true,
  },
}
关键注意点
  • 路由排除:必须排除/login、API路由和/_next/静态资源路径,否则会出现循环拦截或静态资源加载失败的问题。
  • Cookie传递:调用后端校验接口时要传递原请求的Cookie,否则后端无法识别用户登录状态。
  • rewrite vs redirect:rewrite是服务器内部转发,地址栏不变化;redirect是浏览器跳转,地址栏更新。登录校验场景下优先用redirect实现页面跳转。

内容的提问来源于stack exchange,提问作者pragmatic84

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:22:50