Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting 404 when first loading dynamic routes on nextjs

I'm trying to create a blog page to test nextjs and created a dynamic route for the posts, which will be retrieved from Contentful. When navigating from Home page and clicking into a next/router <Link /> component, the blog post loads correctly, but if I get the URL and try loading the page directly from browser address bar, I'll get 404.

Steps to reproduce:

 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

Is this a limitation of NextJS (didn't find anything related to it on documentation) or do we need to configure anything else?

like image 404
Minoru Avatar asked Feb 05 '20 19:02

Minoru


People also ask

How do I return a 404 page from nextjs?

From NextJS 10 onwards, you don't have to return your 404 page explicitly thanks to the new flag notFound: true . You can use it at getStaticProps and getServerSideProps to auto trigger the default 404 page or your own custom 404 page as well.

Can I use next JS on Netlify to generate 404 errors?

For other errors, you can do the exact same thing with an _error.js file in the pages/ directory! The 404 error is special because it is always statically generated, but the others rely on the server. If you'd like to use the server-rendering aspects of Next.js on Netlify, check out our one-click install build plugin.

Why do I get 404's when I add a new page?

The href "goes" to the server to fetch the new page. If you're using some weird routing depending on the href to be different than the actual page location, you're gonna get a 404 the first time the server sees it, as it doesn't recognize that page, once the route kicks in and the correct page is rendered, it will show in the browser.

Why is there a 404 when I use link instead of url?

When you go directly to the URL, the correct route runs first, therefore no 404. When you use a Link instead, the default route runs first and then the correct one, hence the 404. This seems to be a problem with the express integration??


3 Answers

The real issue is that exporting a next app will make it generate static HTML files. Even though it will still be able to request data before rendering the page, the set of available paths are not dynamic (they are generated during the next export command). See this docs and this example.

Based on this, I have 2 possible solutions:

  • generate a webhook to trigger a next build && next export command every time a new blog post is published in Contentful;
  • avoid exporting my next app and host a Node server that will handle the dynamic routes.
like image 69
Minoru Avatar answered Oct 14 '22 18:10

Minoru


That's because when you directly access the link or refresh the page then it add's a slash at the end of route. An next.js doesn't recognize any route like that. To fix this, I hope there should be an easiest way to do that. However you can do this using custom server. Here is an example:

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

Hope this will help you.

like image 27
Muhammad Zeeshan Avatar answered Oct 14 '22 17:10

Muhammad Zeeshan


To extend the answer provided by @Minoru, the official Next documentation covers this case in this example.

Using getStaticPaths and getStaticProps allows you to create dynamic pages at build time, avoiding the 404.

Example code for posts dynamic page:

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;

When building the site with next build && next export we will see in the out folder that Next has created each post page

posts in out folder

Then, when you navigate to /posts/3/ you will see the post with id 3

post with id 3 page

For reference, this docs page contains this case and many other use cases.

like image 29
hmartos Avatar answered Oct 14 '22 18:10

hmartos