htaccess设置环境变量被加REDIRECT_前缀的原因及解决方法
问题描述
我在CentOS 7服务器的.htaccess文件中添加了以下规则,试图根据请求URL设置环境变量:
RewriteRule ^(en|de|fr|ar)/(.*)$ /$2 [E=language:$1]
规则看似生效,但在PHP中读取时,变量名被添加了一次或两次REDIRECT_前缀,变成REDIRECT_REDIRECT_language或REDIRECT_language。
测试URL为http://192.168.2.100/de/test/,重写后$_SERVER[SCRIPT_NAME]的值为/test.php,符合预期,但环境变量依然带有双重REDIRECT_前缀。
我的.htaccess完整内容如下:
Options +FollowSymLinks -MultiViews RewriteEngine on RewriteBase / # ---------------------------------------------------- # server's settings php_value memory_limit 200M php_value max_file_uploads 99 php_value post_max_size 400M php_value upload_max_filesize 400M # ---------------------------------------------------- # Enable gzip <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE text/javascript AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE image/x-icon AddOutputFilterByType DEFLATE image/svg+xml AddOutputFilterByType DEFLATE application/rss+xml AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE application/x-javascript AddOutputFilterByType DEFLATE application/xml AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/x-font AddOutputFilterByType DEFLATE application/x-font-truetype AddOutputFilterByType DEFLATE application/x-font-ttf AddOutputFilterByType DEFLATE application/x-font-otf AddOutputFilterByType DEFLATE application/x-font-opentype AddOutputFilterByType DEFLATE application/vnd.ms-fontobject AddOutputFilterByType DEFLATE font/ttf AddOutputFilterByType DEFLATE font/otf AddOutputFilterByType DEFLATE font/opentype # For Olders Browsers Which Can't Handle Compression BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html </IfModule> # 禁止目录列表 Options -Indexes ErrorDocument 400 /common/page_not_found.php ErrorDocument 401 /common/page_not_found.php ErrorDocument 403 /common/page_not_found.php ErrorDocument 404 /common/page_not_found.php ErrorDocument 500 /common/page_not_found.php RewriteRule ^(en|de|fr|ar)/(.*)$ /$2 [E=language:$1] RewriteRule ^$ /ind.php [END] RewriteRule ^tm/(.*)$ /tmp/$1 [END] RewriteRule ^test/(.*)$ /test.php$1 [END]
最后两条规则已添加END标志,但服务器仍存在多次重写的情况。
我想知道:
- 为什么环境变量会被添加
REDIRECT_前缀? - 如何避免这个问题,获取设置时的原变量名?
原因分析
REDIRECT_前缀是Apache的默认行为:当RewriteRule触发内部重定向(包括后续的重写规则匹配)时,Apache会将之前设置的环境变量重命名,添加REDIRECT_前缀,以此区分原始请求和重定向后的请求环境。
在你的场景中,请求/de/test/首先匹配第一条RewriteRule,设置language=de,然后重写为/test/;接着/test/又匹配最后一条RewriteRule,重写为/test.php——这两次重写触发了两次环境变量的重命名,所以最终得到REDIRECT_REDIRECT_language。
解决方法
方法1:合并规则,避免多次重写
调整规则逻辑,把语言匹配和路径重写一步完成,确保每个请求只触发一次重写:
# 合并语言匹配与test路径重写,设置环境变量后直接跳转 RewriteRule ^(en|de|fr|ar)/test/(.*)$ /test.php$2 [E=language:$1,END] # 处理其他带语言前缀的路径 RewriteRule ^(en|de|fr|ar)/(.*)$ /$2 [E=language:$1,END] # 其他原有规则 RewriteRule ^$ /ind.php [END] RewriteRule ^tm/(.*)$ /tmp/$1 [END]
这样环境变量只会被设置一次,不会触发多次重命名,就能拿到原始的language变量。
方法2:在PHP中提取变量
如果不想修改Rewrite规则,可以在PHP中遍历$_SERVER数组,提取目标变量:
$language = null; // 遍历查找包含language的变量,自动忽略前缀 foreach ($_SERVER as $key => $value) { if (str_ends_with($key, 'language')) { $language = $value; break; } }
方法3:使用PT标志传递环境变量
在语言规则中添加PT(Pass Through)标志,让Apache将重写后的路径视为文件系统路径,减少内部重定向触发的变量重命名:
RewriteRule ^(en|de|fr|ar)/(.*)$ /$2 [E=language:$1,PT]
注意该方法需要确保后续规则能正确匹配重写后的路径,需结合实际环境调整。
内容的提问来源于stack exchange,提问作者fekiri malek

