只是为了澄清一下,这不是一个重复的问题,例如这个因为问题的核心是不同的。我试图做的是将尝试使用语言代码(通常为en
或cz
)访问网站的用户重定向到index.php
设置了语言变量的网站。网站本身只能识别英语和捷克语设置,其他所有语言设置都基于访问者的 IP 地理位置进行重定向(使用外部在线 JSON API)。但问题是,该浏览器不断重定向,并返回错误,指出发生了太多重定向。怎么了?试图寻找错误,但看不到任何错误。
这是完整的.htaccess
文件:
Options -Indexes
RewriteEngine on
RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1
RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301]
RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]
此外,如果用户输入index.php?lang=$1
,我需要将他重定向到更合适的 URL 变体。我在网上搜索过,但对我来说似乎太复杂了 :(
在准备好在线部署之前,我正在 Windows 机器上的 WAMP 服务器中测试网站。
答案1
您实际上并没有声明您请求的触发重定向循环的 URL?
但是,从您发布的指令来看,似乎任何形式的请求/blog<anything>
都会/ftp<anything>
导致重定向循环。
RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301] RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]
Apache mod_rewrite 不支持以下协议相对 URL:RewriteRule
代换- 它们只是被视为根目录相关(即相对于文档根目录的 URL 路径)。您大概会在浏览器的地址栏中看到此重定向循环的结果?它将如下所示:
- 初始请求:
http://example.com/blog/xyz
- 重定向至
http://example.com//blog.czghost.czlh/xyz
- 重定向至
http://example.com//blog.czghost.czlh/.czghost.czlh/xyz
- 重定向至
http://example.com//blog.czghost.czlh/.czghost.czlh/.czghost.czlh/xyz
- ETC。
您需要包含协议。例如:
RewriteRule ^blog/?(.*)$ https://blog.czghost.czlh/$1 [R=301,L]
我还添加了L
( last
) 标志,因为您希望立即触发重定向,而不是冒被进一步重写的风险。这实际上应该在内部重写(重写为index.php
)之前进行。
您需要确保已清除浏览器缓存,因为错误的 301 (永恒的) 重定向将被浏览器缓存。因此,使用 302(临时)重定向进行测试会更容易。
你的blog
和ftp
规则可以通过一个指令来处理,使用交替。 例如:
RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]
RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1
您没有捕获组(即带括号的子模式)RewriteRule
图案,因此$1
反向引用将始终为空。这应该重写为:
RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]
再次,我添加了L
标志,以防止进一步重写。请注意,这要求 URL 路径末尾有一个斜杠后缀。因此,只有格式为/blog/en/
(带有斜杠后缀)的 URL 才能成功重写(尽管这可能无关紧要)。
因此,总而言之,应该将其重写为:
RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]
RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]
另外,如果用户写入
index.php?lang=$1
,我需要将他重定向到良好的 URL 变体。
您可以使用额外的重定向来实现这一点前上述指令。例如:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$
RewriteRule ^(index\.php)?$ /%1/? [R=301,L]
您需要使用RewriteCond
指令来检查查询字符串是否与QUERY_STRING
服务器变量一致(这无法在RewriteRule
指令中完成)。前面对REDIRECT_STATUS
环境变量的检查是为了确保我们只处理初始请求,而不是由后面的指令(将 URL 重写为)重写的请求/index.php?lang=xyz
。REDIRECT_STATUS
初始请求时,环境变量为空,但在第一次成功后设置为“200”(如 200 OK - HTTP 状态)改写。
这将匹配index.php
, 或空的 URL 路径(例如/?lang=xyz
)。%1
是对最后匹配的反向引用条件模式(与之相反的$N
是反向引用RewriteRule
图案)?
在RewriteRule
代换为了从重定向 URL 中删除查询字符串是必要的(或者您也可以QSD
在 Apache 2.4+ 上使用该标志)。
再次强调,最好先使用不会被浏览器缓存的 302(临时)重定向进行测试。
(摘自评论:)唯一正常工作的是
/ftp/
重定向。/blog/
重定向在空白页中保持不变的 URL
您应该确保文件系统上没有同名的物理目录,即。/blog
并且该子目录中没有.htaccess
可以覆盖此目录的其他文件。此外,请确保没有文件共享相同的基本名称blog
。例如blog.html
或blog.php
等等。如果有,则需要确保未启用 MultiViews(mod_negotiation 的一部分)。即。Options -Indexes -MultiViews
如果启用了 MultiViews,则 Apache 将在/blog.php
mod_rewrite 能够重写 URL 之前发出内部子请求(例如)。
概括
Options -Indexes -MultiViews
RewriteEngine on
# Redirect direct requests for "index.php?lang=xyz" to "/xyz/"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$
RewriteRule ^(index\.php)?$ /%1/? [R=301,L]
# Redirect "blog" or "ftp/<anything>" to subdomain
RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]
# Internally rewrite "/xyz/" to "/index.php?lang=xyz"
RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]