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

Next.js动态路由生产环境失效,部署AWS EC2后出现404错误

Next.js生产环境动态路由404问题解决

问题场景

基于Next.js开发的Web应用,后端使用Node.js实现。开发模式下动态路由功能正常,部署到AWS EC2生产环境后,访问如dashboard/seller/4这类动态路由页面返回404错误,应用其余功能均正常,开发模式下API调用无问题。

动态页面文件路径为:

pages
└── dashboard
    └── seller
        └── [seller].tsx

页面核心代码如下:

import { useEffect } from "react";
import { useRouter } from "next/router";
import { hasCookie } from "cookies-next";
import Navbar from "@/components/Navbar";
import Sidebar from "@/components/Sidebar";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { useTranslation } from "next-i18next";
import { type Seller } from "../../../entities/seller";
import { getSellerProfile } from "@/services/seller/getProfile";
import { getAllSellers } from "@/services/seller/getAll";
import { sellerStore } from "@/hooks/sellerState";
import Update from "@/components/Forms/Seller/Update";

export async function getStaticPaths() {
  const data = await getAllSellers();
  if (typeof data === "string") {
    return { paths: [], fallback: false };
  } else {
    const paths = data.map((seller) => {
      return {
        params: {
          id: `${seller.id.toString()}`, // 此处存在参数名不匹配问题
        },
      };
    });
    return { paths, fallback: false };
  }
}

function SellerProfile() {
  const router = useRouter();
  const { t } = useTranslation("models");
  const id = router.query.seller;

  useEffect(() => {
    if (hasCookie("authorization") === false) {
      router.push("/");
    }
  });

  const setName = sellerStore((state) => state.setName);
  const setAge = sellerStore((state) => state.setAge);
  const setLocation = sellerStore((state) => state.setLocation)

  useEffect(() => {
    const fetchData = async () => {
      const response: string | Seller = await getSellerProfile(
        id !== undefined ? +id : 0
      );
      if (typeof response === "string") {
        if (response === "Seller does not exist") {
          alert(t(response))
          window.location.replace("/dashboard/models");
        } else {
          alert(t(response));
        }
      } else {
        const seller: Seller = response;
        setName(seller.name);
        setAge(seller.age);
        setLocation(seller.location)
      }
    };
    fetchData();
  }, []); // 缺少id依赖,路由切换时不会重新获取数据

  return (
    <body className="w-full h-full min-h-screen bg-gray-100 flex flex-row flex-nowrap">
      <aside>
        <Sidebar />
      </aside>
      <main className="w-full h-full">
        <header className="w-full h-auto flex flex-row justify-end items-center">
          <Navbar />
        </header>
        <section className="w-full h-full flex flex-col justify-start items-start relative">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 1440 320"
            className="absolute"
          >
            <path
              fill="#581c87"
              fill-opacity="1"
              d="M0,256L24,224C48,192,96,128,144,117.3C192,107,240,149,288,144C336,139,384,85,432,96C480,107,528,181,576,229.3C624,277,672,299,720,261.3C768,224,816,128,864,85.3C912,43,960,53,1008,74.7C1056,96,1104,128,1152,133.3C1200,139,1248,117,1296,96C1344,75,1392,53,1416,42.7L1440,32L1440,0L1416,0C1392,0,1344,0,1296,0C1248,0,1200,0,1152,0C1104,0,1056,0,1008,0C960,0,912,0,864,0C816,0,768,0,720,0C672,0,624,0,576,0C528,0,480,0,432,0C384,0,336,0,288,0C240,0,192,0,144,0C96,0,48,0,24,0L0,0Z"
            ></path>
          </svg>
          <Update />
        </section>
      </main>
    </body>
  );
}

export async function getStaticProps({ locale }: any) {
  return {
    props: {
      ...(await serverSideTranslations(locale, [
        "common",
        "navbar",
        "models",
      ])),
    },
  };
}

export default SellerProfile;

解决方案

1. 修正getStaticPaths的参数名匹配问题

动态页面文件名为[seller].tsx,意味着路由参数名应为seller,但当前getStaticPaths中返回的params使用的是id,这会导致Next.js无法正确匹配路由。修改getStaticPaths:

export async function getStaticPaths() {
  const data = await getAllSellers();
  if (typeof data === "string") {
    return { paths: [], fallback: false };
  } else {
    const paths = data.map((seller) => {
      return {
        params: {
          seller: `${seller.id.toString()}`, // 将id改为seller,匹配文件名中的参数名
        },
      };
    });
    return { paths, fallback: false };
  }
}

2. 调整fallback配置(可选)

如果卖家数据会在构建完成后新增,当前fallback: false会导致新的卖家ID访问时返回404。可以根据需求设置:

  • fallback: true:允许访问未预渲染的路径,在客户端异步生成页面
  • fallback: 'blocking':服务器端渲染未预渲染的路径,生成后缓存

修改后:

return { paths, fallback: 'blocking' }; // 或true

3. 配置AWS EC2上的服务器重写规则

如果使用Nginx作为反向代理,需要确保所有请求都转发到Next.js的入口文件。在Nginx配置中添加:

location / {
  try_files $uri $uri/ /index.html;
}

如果使用PM2运行Next.js生产服务器,确保服务器正确处理所有路由请求,Next.js默认生产服务器已支持,但额外反向代理需配置重写规则。

4. 修复useEffect依赖问题

当前获取数据的useEffect没有依赖id,从一个卖家页面跳转到另一个时不会重新获取数据。添加id作为依赖:

useEffect(() => {
  // ... 现有fetchData代码
}, [id]); // 添加id依赖

验证步骤

  1. 重新构建应用:npm run build
  2. 部署到AWS EC2
  3. 访问动态路由页面,确认404问题解决

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:45:41