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

问题描述

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

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

  • index.tsx
  • Pricing.tsx

然后,从routing doco开始,我从索引页面向定价页面添加Link,如下所示:

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

这将导致一个类似于example.com/Pricing链接(当您将鼠标悬停在该链接上并单击该链接时,该页面的确会更改为定价页面,并且浏览器在其中显示“ example.com/Pricing”。 URL栏)。

问题是,该链接不是真实的-无法将其添加书签或直接通过网址栏导航到该链接

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

因此,在使用网站时,如果用户尝试为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

解决方法

如果您希望URL是“干净的”并且结尾没有.html,则为备用答案。

要使Next.js默认URL链接与S3 / Cloudfront一起正常工作,必须在next.config.js中配置“添加斜杠”选项:

module.exports = {
  trailingSlash: true,}

按照documentation

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

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

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

这将导致Next.js使用URL example.com/Pricing/-在末尾注意/。 如果许多Web服务器使用默认配置,则它们会在URL中看到尾随index.html字符,从而从该目录提供/

如果您已将S3设置为网站,并且 IFF ,则可以通过website endpoint,as opposed to the REST endpoint访问该URL。

因此,您的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提防带有.个字符的页面。

,

写了这个问题之后,我找到了一个合理的解决方法-尽管我不确定这是否是正确的答案。

Link更改为:

<Link href="/Pricing" as="/Pricing.html">
  <a>Pricing</a>
</Link>

这似乎在本地开发人员中以及将Cloudfront服务的站点添加为书签均有效。仍然感觉有些古怪。我也更喜欢那些非.html的网址。哦,好吧,也许我会改名解决。