Next.js App Router动态路由获取Job详情报错求助
问题:Next.js App Router中职位详情页Slug匹配错误
我正在用Next.js的App Router开发职位详情页,创建了src/app/Job/[slug]/page.js页面,希望通过slug获取对应职位数据。但点击jobsCard.js组件中的链接<Link href={/Job/${slug}}>View job</Link>时,页面出现大量错误,已发布多个职位但无法正常访问详情页。
页面代码(src/app/Job/[slug]/page.js)
async function getJobById(slug) { const response = await fetch(`http://localhost:3000/api/Job/${slug}`, { method: "GET", }); return response.json(); } export default async function JobId({ params }) { const { slug } = await getJobById(params.slug); return ( <> <h1>{slug.pay}</h1> <h1>{slug.aboutCompany}</h1> <h1>{slug.experience}</h1> {/* 其他字段 */} </> ); }
API路由代码(api/route.js)
import { MongoClient } from "mongodb"; import { NextResponse } from "next/server"; export async function POST(req) { try { const chunks = []; for await (const chunk of req.body) { chunks.push(chunk); } const body = Buffer.concat(chunks).toString(); const data = JSON.parse(body); const client = await MongoClient.connect( "mongodb+srv://username:password@cluster0.eikbxrn.mongodb.net/jobupload?retryWrites=true&w=majority&appName=Cluster0" ); const db = client.db(); const propertyCollections = db.collection("jobs"); const result = await propertyCollections.insertOne(data); console.log(result); client.close(); return NextResponse.json({ message: "job uploaded" }); } catch (error) { return NextResponse.json( { error: "Failed to upload job" }, { status: 500 } ); } } export async function GET(request) { const client = await MongoClient.connect( "mongodb+srv://username:password@cluster0.eikbxrn.mongodb.net/jobupload?retryWrites=true&w=majority&appName=Cluster0" ); const db = client.db(); const propertyCollections = db.collection("jobs"); const result = await propertyCollections.find().toArray(); client.close(); return NextResponse.json(result); }
问题根源
- API路由路径不匹配:页面请求的是
/api/Job/${slug},但当前API路由文件在api/route.js,对应路径是/api,而非/api/Job,直接导致请求404。 - GET接口未处理slug参数:现有API的GET方法返回所有职位数组,无法根据slug筛选单个职位,
getJobById拿到的是数组而非单个对象,解构const { slug } = ...会直接报错。 - 数据解构逻辑错误:即便拿到单个职位,代码中试图从返回数据里解构
slug字段,实际应该将整个职位对象赋值给变量,再访问其属性。
修复方案
1. 调整API路由结构与逻辑
将API路由文件移动到src/app/api/Job/route.js,确保路径匹配/api/Job,同时修改GET方法支持slug查询:
import { MongoClient } from "mongodb"; import { NextResponse } from "next/server"; // 复用MongoDB连接,避免重复创建 async function connectToDB() { const client = await MongoClient.connect( "mongodb+srv://username:password@cluster0.eikbxrn.mongodb.net/jobupload?retryWrites=true&w=majority&appName=Cluster0" ); return client.db(); } export async function POST(req) { try { const data = await req.json(); // Next.js 13+可直接用req.json()简化处理 const db = await connectToDB(); const jobCollection = db.collection("jobs"); await jobCollection.insertOne(data); return NextResponse.json({ message: "job uploaded" }); } catch (error) { return NextResponse.json({ error: "Failed to upload job" }, { status: 500 }); } } export async function GET(request) { const { searchParams } = new URL(request.url); const slug = searchParams.get("slug"); const db = await connectToDB(); const jobCollection = db.collection("jobs"); let result; if (slug) { // 根据slug查询单个职位 result = await jobCollection.findOne({ slug }); if (!result) { return NextResponse.json({ error: "Job not found" }, { status: 404 }); } } else { // 无slug时返回所有职位 result = await jobCollection.find().toArray(); } return NextResponse.json(result); }
2. 修正页面数据获取与渲染
修改src/app/Job/[slug]/page.js,正确处理数据请求与渲染:
async function getJobBySlug(slug) { // 使用相对路径,避免硬编码localhost const response = await fetch(`/api/Job?slug=${slug}`, { method: "GET", cache: "no-store", // 禁用缓存,确保获取最新数据 }); if (!response.ok) { throw new Error("Failed to fetch job details"); } return response.json(); } export default async function JobDetail({ params }) { const job = await getJobBySlug(params.slug); return ( <div className="job-detail-container"> <h2>{job.title}</h2> <p>薪资:{job.pay}</p> <h3>关于公司</h3> <p>{job.aboutCompany}</p> <h3>经验要求</h3> <p>{job.experience}</p> {/* 其他职位字段 */} </div> ); }
3. 确保职位数据包含slug字段
发布职位时,需确保每个职位数据中包含唯一的slug字段(可根据职位标题生成,比如转小写、替换空格为短横线),否则无法通过slug匹配到对应职位。
4. 统一路由大小写
Next.js路由区分大小写,建议统一使用小写路径,比如将页面目录改为src/app/job/[slug]/page.js,链接改为:
<Link href={`/job/${slug}`}>View job</Link>
内容的提问来源于stack exchange,提问作者Evan Gordon
相关产品推荐
相关产品推荐

