.htaccess mod_rewrite 重定向过多

.htaccess mod_rewrite 重定向过多

只是为了澄清一下,这不是一个重复的问题,例如这个因为问题的核心是不同的。我试图做的是将尝试使用语言代码(通常为encz)访问网站的用户重定向到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(临时)重定向进行测试会更容易。

你的blogftp规则可以通过一个指令来处理,使用交替。 例如:

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=xyzREDIRECT_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.htmlblog.php等等。如果有,则需要确保未启用 MultiViews(mod_negotiation 的一部分)。即。Options -Indexes -MultiViews如果启用了 MultiViews,则 Apache 将在/blog.phpmod_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]

相关内容