Next.js:托管在 AWS Cloudfront 上时,如何使链接与导出的站点一起使用?

Sho*_*orn 2 amazon-s3 amazon-web-services amazon-cloudfront next.js

我正在尝试通过执行静态 html 导出(即next export),然后将生成的输出复制到 AWS S3 并通过 Cloudfront 提供服务来获得原型 Next.js 项目。

我在/pages目录中有以下两页:

  • index.tsx
  • Pricing.tsx

然后,从路由 doco 开始,Link从索引页面向定价页面添加了一个,如下所示:

<Link href="/Pricing">
  <a>Pricing</a>
</Link>
Run Code Online (Sandbox Code Playgroud)

这会产生一个看起来像这样的链接example.com/Pricing(当您将鼠标悬停在它上面并单击该链接时,该页面确实会更改为定价页面,并且浏览器在 URL 栏中显示“example.com/Pricing”)。

问题是,该链接不是真实的 - 无法直接通过 url 栏添加书签或导航到它。

问题似乎是,当我执行 a 时next export,Next.js.html为每个页面生成一个文件,但路由器不使用这些.html后缀。

因此,在使用该站点时,如果用户尝试添加书签example.com/Pricing;稍后加载该书签将失败,因为 Cloudfront 将返回 404(因为 CF 只知道该.html文件)。

然后我尝试改变我Link的样子:

<Link href="/Pricing.html">
  <a>Pricing</a>
</Link>
Run Code Online (Sandbox Code Playgroud)

这会导致路由器使用example.com/Pricing.html并且与 Cloudfront 一起工作正常 - 但它实际上在本地开发期间导致 404(即使用next dev)!

我可以尝试的其他解决方法是.html在我将它们上传到 S3 之前重命名所有文件并删除扩展名(并确保它们得到一个content-type: text/html标头) - 或者引入一个 Cloudfront lambda,它在.html请求资源时即时进行重命名。我真的不想做 lambda 的事情,但上传前的重命名应该不会太难。

但感觉就像我真的在这里上坡工作。我在基本层面上做错了吗?Next.js 链接应该如何与静态 html 导出一起使用?

Next.js 版本: 9.5.3-canary.23

Sho*_*orn 6

如果您希望您的网址“干净”并且最后没有,请使用替代答案.html

要使 Next.js 默认 URL 链接与 S3/Cloudfront 正常工作,您必须在您的next.config.js.

module.exports = {
  trailingSlash: true,
}
Run Code Online (Sandbox Code Playgroud)

根据文档

将页面导出为 index.html 文件并需要尾部斜杠,/about 变为 /about/index.html 并且可以通过 /about/ 路由。这是 Next.js 9 之前的默认行为。

所以现在您可以将Link定义保留为:

<Link href="/Pricing">
  <a>Pricing</a>
</Link>
Run Code Online (Sandbox Code Playgroud)

这会导致 Next.js 做两件事:

  • 使用 url example.com/Pricing/- 请注意/末尾的
  • index.html在它自己的目录中生成每个页面- 例如/Pricing/index.html

许多 HTML 服务器在其默认配置中,index.html如果/在 URL 中看到尾随字符,就会从匹配目录内部提供。

S3 也会这样做,如果您将其设置为网站,并且IFF您通过网站端点访问 URL ,而不是 REST 端点

所以,你的Cloudfront分布产地必须配置为Origin type = Custom Origin在域像指点example.com.s3-website.us-east-1.amazonaws.com作为S3 Origin

如果您的 Cloudfront/S3 配置错误,当您点击“尾部斜杠”样式的 URL 时,您可能会看到您的浏览器下载了一个binary/octet-stream包含0 bytes.


编辑:注意带有.字符的页面,根据issue 16617