Next.js 13 App Router动态分段获取失败与MongoDB查询报错
问题:Next.js 13 App Router单条数据查询失败,全量查询正常
使用Next.js 13的App Router与API Router,MongoDB作为数据库管理系统。查询集合所有数据时成功,但查询单条数据时失败,报错如下:
TypeError: Cannot read properties of undefined (reading 'id') at GET (webpack-internal:///(sc_server)/./app/api/shop/[id]/route.tsx:14:30) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:265:43) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:111:36) at NoopContextManager.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:360:30) at ContextAPI.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:30:58) at NoopTracer.startActiveSpan (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:953:34) at ProxyTracer.startActiveSpan (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:993:36) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:100:107) at NoopContextManager.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:360:30) at ContextAPI.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:30:58) at NextTracerImpl.trace (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:100:32) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:253:53) at AsyncLocalStorage.run (node:async_hooks:330:14) at Object.wrap (webpack-internal:///(sc_server)/./node_modules/next/dist/server/async-storage/static-generation-async-storage-wrapper.js:41:24) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:207:97) at AsyncLocalStorage.run (node:async_hooks:330:14) at Object.wrap (webpack-internal:///(sc_server)/./node_modules/next/dist/server/async-storage/request-async-storage-wrapper.js:77:24) at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:206:75) at AsyncLocalStorage.run (node:async_hooks:330:14) at AppRouteRouteModule.execute (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:203:56) at AppRouteRouteModule.handle (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:326:41) at RouteHandlerManager.handle (D:\Projects\MyShop\node_modules\next\dist\server\future\route-handler-managers\route-handler-manager.js:28:29) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async doRender (D:\Projects\MyShop\node_modules\next\dist\server\base-server.js:996:38) at async cacheEntry.responseCache.get.incrementalCache.incrementalCache (D:\Projects\MyShop\node_modules\next\dist\server\base-server.js:1172:40) at async D:\Projects\MyShop\node_modules\next\dist\server\response-cache\index.js:99:36
单条数据查询代码(路径:/app/api/shop/[id]/route.tsx)
import { connectToDatabase } from "@/lib/mongo"; import { NextRequest, NextResponse } from "next/server"; import { ObjectId } from "mongodb"; export async function GET (req : NextRequest, res : NextResponse) { try { const id = req.query.id; const client = await connectToDatabase(); const db = client.db("MyShopDB"); // console.log(req); const oneProduct = await db.collection("Products").findOne({ _id: ObjectId(id) }); // return new Response(JSON.stringify(allProducts), { status: 200 }); if(oneProduct) return NextResponse.json(oneProduct) else return res.status(404).json({message: "Products Not Found"}) } catch (error) { console.log(error); return new Response("Failed to fetch all prompts", { status: 500 }) } }
全量数据查询代码(路径:/app/api/shop/route.tsx)
import { connectToDatabase } from "@/lib/mongo"; import { NextRequest, NextResponse } from "next/server"; export async function GET (req: NextRequest, res: NextResponse) { try { const client = await connectToDatabase(); const db = client.db("MyShopDB"); console.log(req); const allProducts = await db.collection("Products").find().toArray(); // return new Response(JSON.stringify(allProducts), { status: 200 }); return NextResponse.json(allProducts); } catch (error) { return new Response("Failed to fetch all prompts", { status: 500 }) } }
解决方案
问题根源
- 动态路由参数获取错误:Next.js 13 App Router的API路由中,动态路由参数(如
[id])并非从req.query获取,而是通过函数的第二个参数params对象获取。原代码错误地将第二个参数定义为res: NextResponse,导致无法拿到路由参数。 - Response对象使用错误:原代码在else分支中使用
res.status(404),但res并非有效的Response对象,应该统一使用NextResponse构建响应。
修正后的代码
import { connectToDatabase } from "@/lib/mongo"; import { NextRequest, NextResponse } from "next/server"; import { ObjectId } from "mongodb"; export async function GET(req: NextRequest, { params }: { params: { id: string } }) { try { const { id } = params; const client = await connectToDatabase(); const db = client.db("MyShopDB"); const oneProduct = await db.collection("Products").findOne({ _id: new ObjectId(id) }); if (oneProduct) { return NextResponse.json(oneProduct); } else { return NextResponse.json({ message: "产品未找到" }, { status: 404 }); } } catch (error) { console.error(error); return NextResponse.json({ message: "获取产品失败" }, { status: 500 }); } }
关键修正点
- 调整GET函数的第二个参数,改为接收包含路由参数的
params对象,从中提取id - 移除错误的
res参数,统一使用NextResponse生成响应 - 实例化
ObjectId时添加new关键字(部分版本允许省略,但更规范) - 优化错误提示文本为中文(可根据需求调整)
内容的提问来源于stack exchange,提问作者Michahide
相关产品推荐
相关产品推荐

