首页 > 解决方案 > Next.js:当托管在 AWS Cloudfront 上时,如何使链接与导出的站点一起使用?

问题描述

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

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

然后,按照路由文档,我Link从索引页面向定价页面添加了一个,如下所示:

<Link href="/Pricing">
  <a>Pricing</a>
</Link>

这会产生一个看起来像这样的链接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>

这会导致路由器使用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

标签: amazon-web-servicesamazon-s3next.jsamazon-cloudfront

解决方案


如果您希望您的 URL 是“干净的”并且最终没有,则可以使用替代答案.html

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

module.exports = {
  trailingSlash: true,
}

根据文档

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

因此,现在您可以将Link定义保留为:

<Link href="/Pricing">
  <a>Pricing</a>
</Link>

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

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

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

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


推荐阅读