首次在 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.
中涵盖了这种情况
使用 getStaticPaths
和 getStaticProps
允许您在构建时创建动态页面,避免 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));
});
})
我正在尝试创建一个博客页面来测试 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.
中涵盖了这种情况使用 getStaticPaths
和 getStaticProps
允许您在构建时创建动态页面,避免 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
作为参考,此 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));
});
})