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

Next.js App Router中食谱详情页404问题求助

解决Next.js App Router食谱详情页404及数据获取错误问题

问题根源

  1. 动态路由目录结构错误:你当前的目录是app > recipes > recipecard,但App Router的动态路由需要创建app/recipes/[slug]/page.tsx的结构,否则访问/recipes/salted-egg-yolks时找不到对应页面,直接触发404。
  2. App Router不兼容getServerSideProps:你在RecipeDetails中使用的getServerSideProps是Pages Router的API,App Router中已不再支持,需要改用Server Component异步获取数据。
  3. 参数逻辑错误:你错误地将URL中的slug(食谱名称)当成了Edamam的uri来解码,实际uri是通过query参数传递的,应该从URL的查询参数中提取。

修复步骤

1. 调整目录结构

创建正确的动态路由页面目录:

app/
└── recipes/
    └── [slug]/
        └── page.tsx  # 将原RecipeDetails组件迁移到这里

2. 修改RecipeCard组件的链接(可选优化)

保持原有逻辑的同时,推荐使用Next.js的结构化路由写法,避免字符串拼接可能的错误:

import React from 'react';
import Link from 'next/link';
import { slugify } from '@/app/utils/slugify';

interface RecipeCardProps {
  recipe: {
    uri: string;
    label: string;
    image: string;
    ingredientLines: string[];
  };
}

const RecipeCard: React.FC<RecipeCardProps> = ({ recipe }) => {
  const slug = slugify(recipe.label);

  return (
    <div className="recipe-card">
      <h3>{recipe.label}</h3>
      <img src={recipe.image} alt={recipe.label} />
      <p>{recipe.ingredientLines.slice(0, 3).join(', ')}...</p>
      {/* 使用结构化路由写法 */}
      <Link 
        href={{
          pathname: '/recipes/[slug]',
          query: {
            slug: slug,
            uri: encodeURIComponent(recipe.uri)
          }
        }}
      >
        View Details
      </Link>
    </div>
  );
};

export default RecipeCard;

3. 重构RecipeDetails为App Router兼容的Server Component

将原RecipeDetails组件迁移到app/recipes/[slug]/page.tsx,改为Server Component并修正参数获取逻辑:

import axios from 'axios';

const APP_ID = process.env.NEXT_PUBLIC_APP_ID;
const APP_KEY = process.env.NEXT_PUBLIC_APP_KEY;

interface Recipe {
  uri: string;
  label: string;
  image: string;
  ingredientLines: string[];
  calories: number;
  totalWeight: number;
  cuisineType: string[];
  mealType: string[];
  dishType: string[];
}

interface PageProps {
  params: { slug: string };
  searchParams: { uri: string };
}

export default async function RecipeDetails({ params, searchParams }: PageProps) {
  // 从查询参数中获取解码后的uri
  const decodedUri = decodeURIComponent(searchParams.uri);
  let recipe: Recipe | null = null;

  try {
    const API_URL = `https://api.edamam.com/api/recipes/v2/by-uri?type=public&app_id=${APP_ID}&app_key=${APP_KEY}&uri=${encodeURIComponent(decodedUri)}`;
    const response = await axios.get(API_URL);
    recipe = response.data.recipe || null;
  } catch (error) {
    console.error('获取食谱详情失败:', error);
  }

  if (!recipe) {
    return <div>未找到该食谱</div>;
  }

  return (
    <div>
      <h1>{recipe.label}</h1>
      <img src={recipe.image} alt={recipe.label} />
      <ul>
        {recipe.ingredientLines.map((ingredient, index) => (
          <li key={index}>{ingredient}</li>
        ))}
      </ul>
      <p><strong>热量:</strong> {recipe.calories.toFixed(2)}</p>
      <p><strong>总重量:</strong> {recipe.totalWeight.toFixed(2)}g</p>
      <p><strong>菜系:</strong> {recipe.cuisineType.join(', ')}</p>
      <p><strong>餐型:</strong> {recipe.mealType.join(', ')}</p>
      <p><strong>菜品类型:</strong> {recipe.dishType.join(', ')}</p>
    </div>
  );
}

关键说明

  • Server Component无需添加'use client'指令,可直接在组件内部异步请求数据,替代Pages Router中的getServerSideProps。
  • 参数通过组件的props直接获取:params对应动态路由的[slug]值,searchParams对应URL中的查询参数。
  • 调用Edamam API时,需要再次对decodedUri进行编码,确保URL参数格式正确。

内容的提问来源于stack exchange,提问作者user17449555

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:00:58