Next.js动态路由权限校验问题:非法相册路径拦截失败
问题解决:Next.js动态路由相册校验与Mongoose报错处理
核心问题分析
你遇到的Cannot read properties of undefined (reading 'User')报错,本质是Next.js Middleware默认运行在Edge Runtime环境,而Mongoose依赖Node.js核心API(如net、fs),这些在Edge环境中不可用,导致模型初始化失败。同时直接在Middleware中操作数据库校验相册的思路不符合Edge Runtime的限制。
可行解决方案
方案1:页面组件内服务端校验(推荐,App Router)
在app/albums/[albumId]/page.js中直接做服务端校验,利用Next.js App Router的服务器组件特性,无需依赖Middleware:
import { notFound, redirect } from 'next/navigation'; import { getAlbumById } from '@/lib/albums'; // 自定义相册查询函数(基于Mongoose) import { getCurrentUser } from '@/lib/auth'; // 获取当前登录用户信息 async function AlbumDetailPage({ params }) { // 1. 校验用户登录状态 const user = await getCurrentUser(); if (!user) { redirect('/login'); } // 2. 校验相册是否存在且属于当前用户 const album = await getAlbumById(params.albumId, user.id); if (!album) { notFound(); // 返回404页面 } // 3. 渲染相册详情 return ( <div> <h1>{album.name}</h1> {/* 相册内容渲染 */} </div> ); } export default AlbumDetailPage;
对应的getAlbumById实现示例:
// lib/albums.js import Album from '@/models/Album'; export async function getAlbumById(albumId, userId) { return await Album.findOne({ _id: albumId, userId }); }
方案2:API Route配合Middleware校验
如果必须用Middleware拦截请求,可通过内部API Route中转数据库操作(API Route默认运行在Node.js环境,支持Mongoose):
步骤1:创建校验API Route
app/api/validate-album/route.js:
import { NextResponse } from 'next/server'; import { getAlbumById } from '@/lib/albums'; import { getCurrentUser } from '@/lib/auth'; export async function POST(request) { const { albumId } = await request.json(); const user = await getCurrentUser(); if (!user) { return NextResponse.json({ valid: false }, { status: 401 }); } const album = await getAlbumById(albumId, user.id); return NextResponse.json({ valid: !!album }); }
步骤2:Middleware中调用API校验
middleware.js:
import { NextResponse } from 'next/server'; export async function middleware(request) { const pathMatch = request.nextUrl.pathname.match(/^\/albums\/([^/]+)$/); if (!pathMatch) return NextResponse.next(); const albumId = pathMatch[1]; // 调用内部校验API const validateRes = await fetch(new URL('/api/validate-album', request.nextUrl.origin), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ albumId }), credentials: 'include', // 携带用户认证Cookie }); const { valid } = await validateRes.json(); if (!valid) { // 校验失败,重定向到相册列表或返回404 return NextResponse.redirect(new URL('/albums', request.nextUrl.origin)); } return NextResponse.next(); } export const config = { matcher: '/albums/:path*', };
方案3:使用MongoDB Edge SDK直接在Middleware操作
如果不想依赖API Route,可改用MongoDB官方Edge SDK(兼容Edge Runtime)直接查询:
// middleware.js import { MongoClient } from 'mongodb'; import { NextResponse } from 'next/server'; import { getUserIdFromRequest } from '@/lib/auth'; // 从请求中提取用户ID(如Cookie/JWT) const client = new MongoClient(process.env.MONGODB_URI); export async function middleware(request) { const pathMatch = request.nextUrl.pathname.match(/^\/albums\/([^/]+)$/); if (!pathMatch) return NextResponse.next(); const albumId = pathMatch[1]; const userId = getUserIdFromRequest(request); if (!userId) return NextResponse.redirect(new URL('/login', request.nextUrl.origin)); // 连接数据库并校验相册 await client.connect(); const db = client.db(); const album = await db.collection('albums').findOne({ _id: albumId, userId }); if (!album) { return NextResponse.redirect(new URL('/albums', request.nextUrl.origin)); } return NextResponse.next(); }
内容的提问来源于stack exchange,提问作者gj_dev
相关产品推荐
相关产品推荐

