Next.js SSG 的正确 .htaccess 设置捕获所有路由

问题描述

我已经建立了一个网站,使用 Next.js 和 SSG - 静态站点生成。 我在 Apache 服务器上为网站提供服务,因此,由于 this answer,我使用以下 .htaccess 配置:

# 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]

# Handling 404
ErrorDocument 404 /my-custom-404.html

而且它一直在完美运行。

但最近,需要一个管理页面,通常的 CRUD。我在没有考虑 SSG 的情况下开发了它(因为实际上不需要它),创建了我自己的自定义路由器并使用 Next.js's catch all routes 来处理这个管理页面的所有内容,我称之为 dashboard.

所以,在我构建的网站上,我有一大堆 page.html 文件一个 /dashboard/[[...dashboard]].html 文件,它是 CRUD 本身(所有子页面内容都是动态导入的) - 因此,每个以 /dashboard 开头的链接都将通过该文件进行处理。

所以,问题是:浏览网站上的链接并进入仪表板,一切正常。但是,如果我尝试直接访问 /dashboard 内的任何链接(例如,包括其自身和子路由:/dashboard/users),它根本不起作用。使用提供的 .htaccess 配置,它直接进入 404。

我尝试了一些添加到 .htaccess 的不同配置,但到目前为止都没有奏效(它仍然直接进入 404,或者浏览器显示错误 ERR_TOO_MANY_REDIRECTS):

RewriteCond %{DOCUMENT_ROOT}/dashboard/$1
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]

这几乎奏效了……但仪表板本身并没有做任何事情(从来没有呈现子页面):

RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]

重要说明:这一切都可以在本地开发服务器上完美运行。

如果有人对我如何解决这个问题有任何建议,我将不胜感激!

解决方法

我已经设法解决了它,至少在可接受的水平上。

正如我在问题中提到的,这几乎可以正常工作(没有呈现子页面,但至少浏览器正确重定向到仪表板):

RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]

从来没有渲染过页面,因为我使用 Next.js 的 withRouter/useRouter 来通知我的自定义路由器当前路由(通过 router.asPath),并且当满足上述规则时,router.asPath被设置为 dashboard/[[...dashboard]].html。 因此,我编写了一个小测试,将使用该 asPath 的任何访问重定向到我的入口点。基本上:

if(router.asPath.contains('[[...dashboard]]')
    router.push('/dashboard')

但是,另一个问题出现了...... 第一个问题解决了:尝试直接访问任何仪表板路线是有效的,但浏览网站(链接)却没有。经过艰苦而漫长的反复试验,我发现我之前的 .htaccess 规则阻止了我的客户端代码请求我的 [[...dashboard]].html 文件。

RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteCond %{REQUEST_URI} !(\[\[\.\.\.dashboard\]\])
RewriteRule (.*) /dashboard/[[...dashboard]].html?p=$1 [L]

基本上:

  • 如果我的请求 URI 包含“仪表板”
  • 如果同一请求不包含 [[...dashboard]]
  • 然后我将其重写为仪表板文件

希望有一天这可以帮助某人!