复杂(?)htaccess重写/重定向

时间:2017-02-15 16:28:54

标签: apache .htaccess redirect mod-rewrite

似乎每隔几周我就要问更多.htaccess重写/重定向问题。每当我想到我理解它时,另一个扳手就会被投入到我的项目中,这表明我不会。

编辑:我原来的问题并不是很清楚,所以以下是为了更加简洁。

目前,所有.html文件都存在于根目录中。例如:http://example.com/about.html

除img,css等普通子目录外,没有任何子目录。

出于跟踪目的,如果有人在http://example.com/random/中输入"随机"可以是任何字符串,我希望他们看到index.html文件,而无需修改网址。目录"随机"根本不存在于服务器上。

about.html等其他网页也是如此。如果有人输入http://example.com/random/about.html,我希望他们看到about.html页。

与此同时,我希望{em} http://example.com/random/abouthttp://example.com/about(缺少文件扩展名)显示关于页面。

但是,如果有人输入的页面不存在,我希望它能使用ErrorDocument

示例:我没有名为" pickups.html"的文件。所以以下都是404s:

http://example.com/pickups.html
http://example.com/pickups
http://example.com/random/pickups.html
http://example.com/random/pickups

如果结束重定向/重写确实剥离了文件扩展名(因为它看起来更好)会很好。

我的想法是,任何以/结尾的请求都只会提供站点根目录下的index.html文件。这样就留下了文件。

我的思维过程是:

  • 从请求中删除文件扩展名
  • 检查站点根目录中是否存在具有扩展名的文件
  • 如果是,则显示该页面。
  • 如果不是,404。

我的初始代码(有帮助)是:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/(.*)$ /$2 [R=301,L]

据我所知,在该代码中,我在最后一个斜杠后抓取所有内容并从文档根目录中提供它。不幸的是,它没有考虑到不存在的文件。

1 个答案:

答案 0 :(得分:2)

从现有文件开始,它们将不加改变地传递。这也可以防止重写循环。

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

接下来是作为可选的虚拟子目录

的一部分请求的现有文件
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]

RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]

这会将请求拆分为可选前缀(.+/)?和文件部分。如果此文件部分存在,可能附加了.html,则表示您已完成。

接下来是带有斜杠的任何内容,只需重写为index.html

RewriteRule /$ /index.html [L]

其他任何内容都是对不存在的文件的请求,这会产生404状态代码。

为了删除可选的.html扩展名并删除现有文件的可选尾部斜杠/,我们必须在开头插入两条规则

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]

这些规则与其他规则类似,只是它们执行重定向R|redirect而不是重写,并且还有一个额外的条件来阻止重写循环。

将所有内容放在一起会产生

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]

RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]

RewriteRule /$ /index.html [L]