Next.js SSG的正确.htaccess配置

时间:2020-07-08 17:08:50

标签: .htaccess next.js

NextJS导出具有以下结构的静态站点:


|-- index.html
|-- article.html
|-- tag.html
|-- article
|   |-- somearticle.html
|   \-- anotherarticle.html
\-- tag
    |-- tag1.html
    \-- tag2.html

我正在使用.htaccess文件隐藏.html扩展名:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html

一切正常,除了:

  • 如果我访问指向domain/article的链接,它将显示article.html页面,但是我的地址栏显示domain/article <-好。
  • 如果刷新,我将发送至地址:domain/article/(请注意斜杠),其中列出了文章目录的内容<-Bad(与Tag相同)
  • 类似地,手动输入domain/article会将我带到domain/article/,而不显示没有扩展名article.html的{​​{1}}。

所以...

  • 我该如何解决?
  • 这是.htaccess问题吗?
  • nextjs配置问题?
  • (NextJS在根目录中创建.html而不是文件会更好吗?)

exportTrailingSlash

我尝试使用似乎相关的article\index.html,但这带来了其他问题,例如,在我所有链接的末尾总是带有斜杠:

例如:如果我去exportTrailingSlash并单击刷新,则(.httaccess?)会在末尾添加一个domain/article/somearticle,使我/并不可怕,只是不太干净并且不一致...

编辑: 实际上,这有点可怕,因为有时我们会在结尾加上斜杠,有时我们不在nextjs链接上……必定是某种东西关于我如何使用domain/article/somearticle/的信息,但我无法弄清楚。

无论如何,我尝试过的<Link />规则中的每一个都始终成功地删除尾随斜杠...


更多详细信息:

在我的下一个应用中,我有文件夹:

.htaccess

在各个页面中,我使用nextJS Link组件:

/articles/
   [slug].js
   index.js

2 个答案:

答案 0 :(得分:6)

如果您请求/article并且/article作为物理目录存在,则Apache的mod_dir(默认情况下)将附加尾部斜杠以“修复” URL。这是通过301永久重定向实现的-因此它将被浏览器缓存。

尽管具有与文件相同的基本名称的物理目录,并使用无扩展名的URL会产生歧义。例如。是/article访问目录/article/还是文件/article.html。无论如何,您似乎都不想允许直接访问目录,因此这似乎可以解决这种歧义。

要防止Apache mod_dir将斜杠附加到目录中,我们需要禁用DirectorySlash。例如:

DirectorySlash Off

但是如上所述,如果您以前访问过/article,则到/article/的重定向将已经被浏览器缓存-因此,您需要先清除浏览器缓存,然后才能生效。

由于要删除文件扩展名,因此还需要确保禁用MultiViews,否则,mod_negotiation将对基础文件发出内部子请求,并可能与mod_rewrite冲突。默认情况下,MultiViews是禁用的,尽管某些共享主机出于某些原因会启用它。从输出中可以看到,它似乎没有启用MultiViews,但是最好确保...

# Ensure that MutliViews is disabled
Options -MultiViews

但是,如果您需要能够访问目录本身,则需要使用内部重写手动附加尾部斜杠。尽管这似乎不是这里的要求。但是,您应该确保禁用目录列表:

# Disable directory listings
Options -Indexes

尝试访问任何目录(最终未映射到文件-参见下文)并且不包含DirectoryIndex文档,将返回403 Forbidden响应,而不是目录列表。

请注意,在链接到domain/article的链接,刷新页面和手动键入domain/article之间,唯一可能出现的区别是浏览器正在缓存 ... 任何中间代理缓存。 (除非您有JavaScript可以拦截锚点上的click事件?!)

您仍然需要将请求从/foo重写为/foo.html或将/foo重写为/foo/index.html(请参见下文),具体取决于您配置站点的方式。尽管您最好选择其中一个,而不要同时选择两者(就像您可能暗示的那样)。

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html

目前还不清楚这对您当前的工作方式如何-除非您看到缓存的响应?当您请求/article时,第一个条件失败,因为该条件作为物理目录存在并且未处理该规则。即使启用了MultiViews,mod_dir也将具有优先级并附加斜杠。

检查.html文件是否存在的第二个条件不一定是检查要重写的文件。例如。如果您请求/foo/bar(其中存在/foo.html,但是没有物理目录/foo,则RewriteCond指令将检查/foo.html的存在-成功) ,但是请求在内部被重写为/foo/bar.html(从捕获的RewriteRule 模式)-这导致内部重写循环,并向客户端返回500错误响应。请参见my answerfollowing ServerFault question,其中会详细介绍此处实际发生的情况。

如果我们假设任何包含看起来像文件扩展名的URL(例如,静态资源.css.js和图像文件)都应被忽略,我们还可以进行进一步的优化,否则我们正在对每个请求执行文件系统检查,这相对昂贵。

因此,为了将/article格式的请求映射(内部重写)到/article.html并将/article/somearticle映射到/article/somearticle.html像这样:

# Rewrite /foo to /foo.html if it exists
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.html [L]

RewriteCond TestString 中不需要反斜杠转义文字点-此处的点没有特殊含义;它不是正则表达式。

然后,要处理应映射到/foo的{​​{1}}格式的请求,您可以执行以下操作:

/foo/index.html

通常,您将允许mod_dir服务# Rewrite /foo to /foo/index.html if it exists RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/index.html [L] (例如DirectoryIndex),但是在目录中省略了斜杠,这可能会出现问题。

摘要

将以上几点结合在一起,我们就有:

index.html

这可能会进一步优化,具体取决于您的站点结构以及是否要向# Disable directory indexes and MultiViews Options -Indexes -MultiViews # Prevent mod_dir appending a slash to directory requests DirectorySlash Off # Rewrite /foo to /foo.html if it exists RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.html [L] # Otherwise, rewrite /foo to /foo/index.html if it exists RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/index.html [L] 文件添加其他指令。例如:

  1. 您可以在文件顶部的请求的URL上检查文件扩展名,以防止进一步处理。然后可以“简化”每个后续规则上的.htaccess正则表达式。
  2. 包含斜杠的请求可能会被阻止或重定向(以删除斜杠)。
  3. 如果请求是一个RewriteRule文件,则重定向到无扩展名URL。如果您同时处理.html/foo.html,则这会变得有些复杂。但这仅在您更改现有URL结构时才真正必要。

例如,实现上面的#1和#2,将使指令的编写方式如下:

/foo/index.html

在更改为301(永久)重定向之前,请始终使用302(临时)重定向进行测试,以避免缓存问题。

答案 1 :(得分:0)

  • (NextJS在根目录中创建article\index.html而不是文件会更好吗?)

是的!接下来为您can do that

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

要返回并添加斜杠,请打开next.config.js,然后 启用exportTrailingSlash配置:

module.exports = { exportTrailingSlash: true, }