首次在 nextjs 上加载动态路由时获取 404

Getting 404 when first loading dynamic routes on nextjs

我正在尝试创建一个博客页面来测试 nextjs 并为 post 创建一个动态路由,该路由将从 Contentful 中检索。从主页导航并单击 next/router <Link /> 组件时,博客 post 加载正确,但如果我得到 URL 并尝试直接从浏览器地址加载页面酒吧,我会得到 404。

重现步骤:

 1. git clone https://github.com/zeit/next-learn-demo.git
 2. cd next-learn-demo/8-deploying
 3. yarn
 4. next build && next export
 5. cd out
 6. serve
 7. Navigate to http://localhost:5000/p/learn-nextjs
 8. See 404

这是 NextJS 的局限性(在文档中没有找到任何相关内容)还是我们需要配置其他任何东西?

那是因为当您直接访问 link 或刷新页面时,它会在路由末尾添加一个斜线。 next.js 无法识别任何类似的路线。为了解决这个问题,我希望应该有一个最简单的方法来做到这一点。但是,您可以使用 custom server 来执行此操作。这是一个例子:

server.get("/about/", (req, res) => {
  return app.render(req, res, "/about")
});

希望对您有所帮助。

真正的问题是导出 next 应用程序会使其生成静态 HTML 文件。尽管它仍然能够在呈现页面之前请求数据,但可用路径集不是动态的(它们是在 next export 命令期间生成的)。看到这个 docs and this example.

基于此,我有两种可能的解决方案:

  • 每次在 Contentful 中发布新博客 post 时,生成一个 webhook 以触发 next build && next export 命令;
  • 避免导出我的 next 应用程序并托管一个将处理动态路由的节点服务器。

为了扩展@Minoru 提供的答案,Next 官方文档在 example.

中涵盖了这种情况

使用 getStaticPathsgetStaticProps 允许您在构建时创建动态页面,避免 404。

posts 动态页面的示例代码:

import { GetStaticPaths, GetStaticProps } from 'next';

const Post = ({ post }) => {
    const { id, content } = post;

    return (
        <div>
            <h1>Post {id}</h1>
            <p>{content}</p>
        </div>
    );
};

export const getStaticPaths: GetStaticPaths = async () => {
    // Get all posts via API, file, etc.
    const posts = [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }, { id: '5' }]; // Example
    const paths = posts.map(post => ({
        params: { id: post.id },
    }));
    return { paths, fallback: false };
};

export const getStaticProps: GetStaticProps = async context => {
    const postId = context.params?.id || '';
    // Get post detail via API, file, etc.
    const post = { id: postId, content: `I'm the post with id ${postId}!` }; // Example
    return { props: { post } };
};

export default Post;

使用 next build && next export 构建站点时,我们将在 out 文件夹中看到 Next 创建的每个 post 页面

然后,当您导航到 /posts/3/ 时,您将看到 ID 为 3

的 post

作为参考,此 docs 页面包含此案例和许多其他用例。

不想违反任何旧的帖子规则,但以防万一在我的上下文中我使用 vercel 的功能 webhook 进行新部署,并且因为我使用的是 firebase,所以我创建了一个简单的 firebase function whith is hooked to a new event creation of a page triggers the webhook. I've used fetch because we can make a GET request according to the docs

exports.newEventAdded = functions.region('us-central1').firestore.document('local_events/{localeventId}')
.onCreate((snap, context) => {
    fetch('https://api.vercel.com/v1/integrations/deploy/process.env.NEXT_PUBLIC_VERCEL_WEBHOOK_ID')
        .then(function (response) {
            return response.json();
        })
        .then(function (myJson) {
            console.log(JSON.stringify(myJson));
        });
})