NextJS报错TypeError: Cannot read 'replace' of undefined求助
出现错误:Server Error TypeError: Cannot read properties of undefined (reading 'replace'),不知道从哪入手调试。
原本系统运行正常,尝试在Cookie Token中添加用户套餐信息以设置Premium用户时失败,移除middleware后系统恢复正常,求指导定位问题。
错误截图:
middleware.ts 代码
const handleI18nRouting = createMiddleware(routing); function detectLocale(req: NextRequest) { const country = req.headers.get('x-vercel-ip-country'); if (country === 'VN') return 'vi'; if (country === 'CN') return 'zh'; // 本地运行时的 fallback const language = req.headers.get('accept-language'); if (language?.startsWith('vi')) return 'vi'; if (language?.startsWith('zh')) return 'zh'; return 'en'; } export async function middleware(req: NextRequest) { const path = req.nextUrl.pathname; // 跳过 api 和 static 文件 if ( path.startsWith('/api') || path.startsWith('/_next') || path.includes('.') ) { return NextResponse.next(); } // 检查是否已有 locale const hasLocale = /^\/(vi|zh)(\/|$)/.test(path); if (!hasLocale) { const locale = detectLocale(req); // 英文对应根路径 if (locale === 'en') { return handleI18nRouting(req); } const url = req.nextUrl.clone(); url.pathname = `/${locale}${path}`; return NextResponse.redirect(url); } console.log('4'); // 验证会话 const session = await verifySession(); const isAdminRoute = Object.values(adminUrl).some( p => path === p || path.startsWith(`${p}/`), ); const isProtectedRoute = Object.values(protectedUrl).some( p => path === p || path.startsWith(`${p}/`), ); const authPages = [ '/authentication/sign-in', '/authentication/sign-up', '/authentication/forgot-password', ]; const isAuthPage = authPages.includes(path); if (!session && (isProtectedRoute || isAdminRoute)) { return NextResponse.redirect(new URL('/authentication/sign-in', req.url)); } if (session && isAdminRoute && !session.isAdmin) { return NextResponse.rewrite(new URL('/unauthorized', req.url)); } if (session && isAuthPage) { return NextResponse.redirect(new URL('/', req.url)); } return handleI18nRouting(req); } export const config = { matcher: ['/((?!api|_next|_vercel|.*\\..*).*)'], };
verifySession.ts 代码
import { cookies } from 'next/headers'; import { cache } from 'react'; import { decrypt } from './session'; type SessionPayload = { userId: string; isAdmin: boolean; subscriptionTier?: string; subscriptionExpiredAt?: string | Date; }; export const verifySession = cache(async () => { try { const cookie = (await cookies()).get('session')?.value; if (!cookie || typeof cookie !== 'string') return null; const session = (await decrypt(cookie)) as SessionPayload; if (!session?.userId) { return null; } const expiredAt = session.subscriptionExpiredAt ? new Date(session.subscriptionExpiredAt) : null; const isVip = expiredAt ? expiredAt > new Date() : false; return { isAuth: true, userId: session.userId, isAdmin: session.isAdmin, isVip, subscriptionTier: session.subscriptionTier ?? 'FREE', subscriptionExpiredAt: expiredAt, }; } catch (error) { console.error('verifySession error:', error); return null; } });
decrypt.ts 代码
export async function decrypt(token: string) { if (!token || typeof token !== 'string') { throw new Error('Invalid token input'); } try { const { payload } = await jwtDecrypt(token, ENC_KEY); if (!payload?.jws || typeof payload.jws !== 'string') { throw new Error('Invalid token structure'); } const { payload: verifiedPayload } = await jwtVerify(payload.jws, SIGN_KEY); return verifiedPayload; } catch (err) { console.error('DECRYPT ERROR:', err); throw err; } }
调试建议
定位
replace调用点
错误提示是调用undefined的replace方法,你贴的代码里没直接出现,但大概率是handleI18nRouting内部逻辑,或者jwtDecrypt/jwtVerify库的内部代码触发的。可以在浏览器DevTools的错误栈里找具体的调用位置,或者在代码中逐步注释逻辑,看哪一步触发错误。检查Token结构的兼容性
你新增了套餐字段,要确认:- 旧Token(未包含新字段)是否能正常解密,会不会因为字段缺失导致后续逻辑出错
- 新生成的Token中
subscriptionExpiredAt是否是合法的ISO日期字符串,避免new Date()解析出错
加日志排查Session验证流程
在verifySession里添加日志,打印解密后的session对象:const session = (await decrypt(cookie)) as SessionPayload; console.log('Decrypted session data:', session); // 新增这行看
session是否有undefined的字段,比如isAdmin会不会变成undefined,导致后续判断逻辑异常。逐步隔离middleware逻辑
先注释掉const session = await verifySession();及之后的所有会话验证逻辑,看系统是否正常。如果正常,再逐步恢复每一段逻辑,比如先恢复session获取,再恢复路由判断,找到触发错误的具体代码块。处理解密异常的边界情况
decrypt函数抛出错误时,verifySession返回null,但要确认错误是否会传播到上层逻辑。可以在decrypt里捕获错误后返回null,而不是抛出,或者在verifySession里更细致地处理不同类型的错误。
内容的提问来源于stack exchange,提问作者Khuong Viet Tai

