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

NextJS13 + Prisma数据获取报500错误,无法映射地区与城市数据

修复NextJS13 + Prisma 500错误的步骤

1. 修正API路由(核心问题)

你的api/regions路由存在两个关键错误:

  • 错误返回req而非数据响应
  • 错误使用NextApiResponse(App Router下应使用NextResponse)

修复后的App Router API路由

import { NextResponse } from 'next/server';
import prismadb from '@/lib/prismadb';

export async function GET() {
  try {
    const regions = await prismadb.region.findMany({
      include: { villes: true },
    });
    return NextResponse.json(regions);
  } catch (error) {
    console.error('Error fetching regions:', error);
    return NextResponse.json({ error: 'Failed to fetch regions' }, { status: 500 });
  }
}

若使用Pages Router,API路由应改为

import type { NextApiRequest, NextApiResponse } from 'next';
import prismadb from '@/lib/prismadb';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'GET') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const regions = await prismadb.region.findMany({
      include: { villes: true },
    });
    res.status(200).json(regions);
  } catch (error) {
    console.error('Error fetching regions:', error);
    res.status(500).json({ error: 'Failed to fetch regions' });
  }
}

2. 优化组件数据获取逻辑

方案一:App Router(推荐)

NextJS13 App Router不支持getServerSideProps,需拆分组件:

  • 用Server Component直接调用Prisma获取数据
  • 用Client Component处理交互状态

Server Component(页面/父组件)

import CandidatureClient from './CandidatureClient';
import prismadb from '@/lib/prismadb';

async function CandidaturePage() {
  const regions = await prismadb.region.findMany({
    include: { villes: true },
  });

  return <CandidatureClient regions={regions} />;
}

export default CandidaturePage;

Client Component(交互逻辑)

去掉冗余的villes props,修复map的key和图片路径:

'use client';

import React, { useState } from "react";
import Link from "next/link";
import Image from "next/image";

interface Ville {
  id: number;
  name: string;
  startDate: string;
  endDate: string;
  programStartDate: string;
  link: string;
}

interface Region {
  id: number;
  name: string;
  villes: Ville[];
}

interface Props {
  regions: Region[];
}

function toClassName(name: string) {
  return name.replace(/ /g, "_");
}

const CandidatureClient: React.FC<Props> = ({ regions }) => {
  const [stage, setStage] = useState<"REGION" | "VILLE" | "JOIN">("REGION");
  const [selectedRegion, setSelectedRegion] = useState<Region | null>(null);
  const [selectedVille, setSelectedVille] = useState<Ville | null>(null);

  const selectRegion = (region: Region) => {
    setSelectedRegion(region);
    setStage("VILLE");
  };

  const selectVille = (ville: Ville) => {
    setSelectedVille(ville);
    setStage("JOIN");
  };

  return (
    <section className={`Section-Candidature ${stage}`}>
      <div className="Choice">
        <button className={stage === "REGION" ? "active" : ""}>CHOISIS TA REGION</button>
        <button className={stage === "VILLE" ? "active" : ""}>CHOISIS TA VILLE</button>
        <button className={stage === "JOIN" ? "active" : ""}>REJOINS NOUS!</button>
      </div>

      {stage === "REGION" && (
        <div className="FrancePays">
          {regions.map((region) => (
            <div key={region.id} className={toClassName(region.name)}>
              <p>{region.name}</p>
              <Image
                src="/SVG/flecheBlanche.svg"
                alt="Flèche blanche"
                width={40}
                height={40}
                className="Fleches"
                onClick={() => selectRegion(region)}
              />
            </div>
          ))}
        </div>
      )}

      {stage === "VILLE" && selectedRegion && (
        <div className="FranceRegion">
          {selectedRegion.villes.map((ville) => (
            <div key={ville.id} className={toClassName(ville.name)}>
              <p>{ville.name}</p>
              <Image
                src="/SVG/flecheBlanche.svg"
                alt="Flèche blanche"
                width={40}
                height={40}
                className="Fleches"
                onClick={() => selectVille(ville)}
              />
            </div>
          ))}
        </div>
      )}

      {stage === "JOIN" && selectedVille && (
        <div className="Join">
          <div className="TroisSemaines">
            <p>3</p>
            <p>SEMAINES DE FORMATION INTENSIVE</p>
          </div>
          <div className="CinqMois">
            <p>5</p>
            <p>MOIS D'ACCOMPAGNEMENT</p>
          </div>
          <div className="Annee">
            <p>DECOUVRE LA PROMO 2023</p>
            <Image
              src='/assets/Annee.png'
              alt='Année'
              fill
              objectFit='cover'
              placeholder="blur"
              blurDataURL={'/assets/Annee.png'}
              className='Determines'
            />
          </div>
          <div className="Debut">
            <p>{selectedVille.startDate}</p>
            <p>DEBUT APPEL CANDIDATURE</p>
          </div>
          <div className="Fin">
            <p>{selectedVille.endDate}</p>
            <p>FIN APPEL CANDIDATURE</p>
          </div>
          <div className="Formation">
            <p>{selectedVille.programStartDate}</p>
            <p>FORMATION INTENSIVE DE 6 MOIS</p>
          </div>
          <div className="Lien">
            <p>JE POSTULE</p>
            <Link href={selectedVille.link} target="_blank" >
              <Image
                src='/SVG/flecheBlanche.svg'
                alt='Flèche blanche'
                fill
                objectFit='contain'
                placeholder="blur"
                blurDataURL={'/SVG/flecheBlanche.svg'}
                className='Fleches'
              />
            </Link>
          </div>
        </div>
      )}
    
    </section>
  );
};

export default CandidatureClient;

方案二:Pages Router

直接在getServerSideProps中调用Prisma,避免本地API请求:

// 组件代码保留,修改getServerSideProps
export const getServerSideProps = async () => {
  try {
    const regions = await prismadb.region.findMany({
      include: { villes: true },
    });

    return {
      props: {
        regions,
      },
    };
  } catch (error) {
    console.error("Error fetching data:", error);
    return {
      props: {
        regions: [],
      },
    };
  }
};

3. 额外检查项

  • 确保prismadb初始化正确,采用单例模式避免重复实例化
  • 验证.env文件中DATABASE_URL数据库连接字符串配置正确
  • 运行npx prisma generate更新Prisma客户端
  • 运行npx prisma db push或npx prisma migrate deploy同步数据库schema

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 10:44:54