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

Next.js App Router用Clerk中间件时Vercel生产环境返回404本地正常

Next.js App Router + Clerk中间件在Vercel生产环境导致404问题排查与解决

问题场景

使用Next.js App Router搭配Clerk身份验证,本地npm run dev环境下所有路由正常访问,但部署到Vercel生产环境后,/about、/products、/contact、/cart等路由均返回404错误。构建日志显示所有路由已正确生成,移除Clerk中间件后问题消失,且Vercel环境变量配置无误。

项目结构:

src/app/about/page.js
src/app/products/page.js
src/app/products/[proid]/page.js
src/app/contact/page.js
src/app/cart/page.js

原中间件代码:

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

const isPublicRoute = createRouteMatcher([
  '/',
  '/about',
  '/products(.*)',
  '/contact',
  '/cart',
  '/sign-in(.*)',
  '/sign-up(.*)',
]);

export default clerkMiddleware((auth, req) => {
  if (!isPublicRoute(req)) {
    return auth().protect();
  }
});

export const config = {
  matcher: ["/((?!_next|.*\\..*).*)"]
};

原因分析

核心问题在于中间件的路由匹配范围与Vercel生产环境的静态路由处理逻辑冲突:

  1. 原config.matcher匹配了所有非静态资源、非Next.js内部路由的请求,包括静态生成的公共路由(如/about)。在Vercel生产环境中,静态路由由CDN直接返回,但中间件会先拦截所有匹配的请求,若Clerk的路由匹配逻辑在生产环境存在解析差异,会导致请求无法正确传递到静态资源服务,返回404。
  2. createRouteMatcher中使用的(.*)正则写法,可能与Clerk在生产环境的路由匹配规则不完全兼容,导致公共路由被误判为非公共路由,触发auth().protect()后因未登录逻辑跳转异常,最终返回404。

解决方案

1. 缩小中间件匹配范围(推荐)

只让中间件处理需要身份验证的路由,避免干扰静态公共路由:

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

// 定义需要保护的路由(示例:假设/dashboard、/account需要登录)
const isProtectedRoute = createRouteMatcher([
  '/dashboard/:path*',
  '/account/:path*'
]);

export default clerkMiddleware((auth, req) => {
  // 仅对受保护路由应用身份验证
  if (isProtectedRoute(req)) {
    return auth().protect();
  }
});

export const config = {
  // 只匹配需要保护的路由,公共静态路由直接由Vercel CDN处理
  matcher: ['/dashboard/:path*', '/account/:path*']
};

2. 修正公共路由匹配规则

若仍需让中间件覆盖所有路由,需调整createRouteMatcher的路由写法为Next.js兼容的格式:

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

// 使用Next.js风格的通配符语法`:path*`替代正则`(.*)`
const isPublicRoute = createRouteMatcher([
  '/',
  '/about',
  '/products/:path*',
  '/contact',
  '/cart',
  '/sign-in/:path*',
  '/sign-up/:path*',
]);

export default clerkMiddleware((auth, req) => {
  if (!isPublicRoute(req)) {
    return auth().protect();
  }
});

export const config = {
  matcher: ["/((?!_next|.*\\..*).*)"]
};

3. 升级Clerk依赖版本

确保使用最新版@clerk/nextjs,修复可能存在的生产环境适配问题:

npm install @clerk/nextjs@latest

验证步骤

  1. 修改中间件代码后,本地运行npm run build && npm start模拟生产环境,确认路由正常访问。
  2. 重新部署到Vercel,检查生产环境下公共路由是否返回200。
  3. 若问题仍存在,可在中间件中添加日志(如console.log('Path:', req.nextUrl.pathname, 'Is public:', isPublicRoute(req))),查看Vercel函数日志中的请求路径与匹配结果,定位具体问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 12:22:29