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

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);
}

问题根源

  1. API路由路径不匹配:页面请求的是/api/Job/${slug},但当前API路由文件在api/route.js,对应路径是/api,而非/api/Job,直接导致请求404。
  2. GET接口未处理slug参数:现有API的GET方法返回所有职位数组,无法根据slug筛选单个职位,getJobById拿到的是数组而非单个对象,解构const { slug } = ...会直接报错。
  3. 数据解构逻辑错误:即便拿到单个职位,代码中试图从返回数据里解构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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:17:52