当应用程序导出为静态文件时,动态路由无法正常工作。

3

我有一个静态导出并且具有动态路由的网站。

这个网站在开发模式下运行良好。但是,如果我构建和导出它,然后serve静态文件,它会出现问题。

您可以转到网站根目录并单击链接,它将带您转到像http://localhost:3000/post/1这样的动态帖子页面,并且会正常工作,但是如果您刷新页面(或直接访问),它会出现404错误。

enter image description here

为什么会这样呢?需要访问路由查询对象的动态路由在静态导出时无法工作吗?

动态路由文档没有提到使用静态导出时动态路由的任何注意事项。

代码:

首先,以next.js静态示例为起点,我编辑了pages/post/[id].tsx文件,删除了getStaticPathsgetStaticProps(因为我不需要构建时静态生成),并在挂载时添加了客户端获取。我正在获取router.query.id值并使用它来获取数据:

⚡ Codesandbox 这里(在开发中可以正常工作, 但是导出后如果在服务器上运行就会出错)

import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { GetPost } from '../../lib/postdata_api'
import { PostData } from '../../types/postdata'

const Post = () => {
  const [postData, setPostData] = useState<null | PostData>(null)
  const router = useRouter()
  const id = router.query.id as string
  const fetchData = async () => setPostData(await GetPost(id))

  useEffect(() => {
    if (!router.isReady) return
    fetchData()
  }, [router, router.isReady])

  if (!postData) return 'Loading...'

  return (
    <main>
      <Head>
        <title>{postData.title}</title>
      </Head>

      <h1>{postData.title}</h1>

      <p>{postData.body}</p>

      <Link href="/">
        <a>Go back to home</a>
      </Link>
    </main>
  )
}

export default Post

期望行为

我期望它的行为与开发环境中一样。也就是说,用户可以:

  • 在根页面上点击链接
  • 查看动态发布页面,例如/post/1
  • 刷新或直接访问此文章(而不是出现404错误)

复现步骤

  • 下载代码沙盒GitHub存储库
  • 运行npm run export && serve out
  • 访问http://localhost:3000
  • 点击文章链接
  • 按下刷新键以查看404错误

请尝试在页面链接后加上斜杠再访问该页面,谢谢。 - Irfanullah Jan
@IrfanullahJan 好主意!但可悲的是,这并没有改变任何事情。 - Ash
2个回答

2

简而言之

将以下配置添加到next.config.js中,然后再次进行导出:

// next.config.js
module.exports = {
    trailingSlash: true,
}

说明

可以通过手动更改导出过程生成的所有路由为文件夹并将每个*.html文件重命名为index.html来修复此行为,如下所示:

next export生成的路由:

/posts/1.html

“固定”路由:

/posts/1/index.html

如果浏览器的url为/posts/1,当页面被刷新时,路由将会获得一个尾随斜杠并变成/posts/1/。由于HTTP服务器默认选择任何目录下的index.html文件,因此HTTP请求将被正确处理,并显示静态页面。

显然,在Next.js v9之前的导出中,默认情况下存在这种行为,可以通过向next.config.js文件添加以下配置来启用(以避免手动更改每个路由):

// next.config.js
module.exports = {
    trailingSlash: true,
}

我知道有点晚了,但昨天我遇到同样的问题时发现了这个解决方案。
来源:官方文档

1

我看到你在使用来自Vercel的'serve'。为了拥有漂亮的URL,你需要为服务器配置重写。

根据这个指南https://github.com/vercel/serve-handler#rewrites-array。你需要添加这个配置才能让它与漂亮的URL一起工作。

// public/serve.json
{
  "rewrites": [
    { "source": "/post/*", "destination": "/post/[id].html" }
  ]
}

谢谢回复!既然在开发模式下按预期工作,为什么我需要这样做呢?不确定为什么我需要指定重写,因为我并没有试图“将传入的请求路径映射到不同的目标路径”。感谢您的帮助! - Ash
因为你选择将其导出并作为静态文件提供,所以你会失去一些功能,比如重写URL。请阅读https://blog.logrocket.com/understanding-static-html-export-next-js/中的“Next.js静态HTML导出不支持的功能”部分。因此,你需要配置“serve”(你的Web服务器)来重新实现重写URL特性。 - vuxlee
你可以使用next start来使用next webserver,它(可能)与dev模式相同,但没有热加载等功能... https://nextjs.org/docs/api-reference/cli - vuxlee
那个不起作用。它使页面读取路由查询对象为{query:{id:“[id] .html”}},这会破坏任何客户端数据获取,因为它试图获取“https://jsonplaceholder.typicode.com/posts/[id].html”。 - Ash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接