DirectoryMatch
指令通常对我来说效果很好。
但是,当与
RewriteRule
结合使用时,它可能会失败。我也不明白为什么。
现在,我并不是在寻求一种完全避免
DirectoryMatch
指令的解决方法,例如通过组合 Directory
和 Import
指令。
我的问题特别是关于
DirectoryMatch
指令。为了让它发挥作用,我缺少什么?我对此有什么不明白的地方?关于重写模块?还是别的什么?
顺便说一下,请注意,链接
RewriteRule
并不能使 DirectoryMatch
指令成功实现此目的。
不允许使用
.htaccess
文件。 (/etc/apache2/apache2.conf
包含 AllowOverride None
指令。)
我已上传以下文件。它们已经被 gzip 压缩了:
$ ls -dlU `find test-{d,m}*`
drwxr-xr-x 2 root root 4096 Feb 9 06:07 test-directory
-rw-r--r-- 1 root root 439 Feb 8 14:17 test-directory/test.html.gz
drwxr-xr-x 2 root root 4096 Feb 9 06:06 test-match
-rw-r--r-- 1 root root 439 Feb 8 14:18 test-match/test.html.gz
我在
/etc/apache2/conf-available/local-settings.conf
中有这些设置:
RewriteEngine On
<Directory /var/www/html>
Require all granted
</Directory>
<Directory /var/www/html/test-directory>
LogLevel debug
Header set Cache-Control no-store
RewriteCond "%{REQUEST_FILENAME}.gz" -s
RewriteRule ^test\.html$ $0.gz
RewriteRule ^test\.html\.gz$ - [T=text/html,E=no-gzip:1]
</Directory>
<DirectoryMatch "^/var/www/html/test-match">
LogLevel debug
Header set Cache-Control no-store
RewriteCond "%{REQUEST_FILENAME}.gz" -s
RewriteRule ^test\.html$ $0.gz
RewriteRule ^test\.html\.gz$ - [T=text/html,E=no-gzip:1]
</DirectoryMatch>
基本上,如果附加到请求的文件名时隐式
.gz
扩展名作为文件存在,则:
Append `.gz`;
Serve the correct media type; and
Prevent mod_deflate from double-gzipping.
导航至
test.html
下的 Directory
有效。但在 DirectoryMatch
下它会生成“404 Not Found”。错误日志显示:
$ sudo tail -n 1 /var/log/apache2/error.log
[{...}:07:45.669167 2024] [core:info] [pid 919696:tid 281473097625984] {...} AH00128: File does not exist: /var/www/html/test-match/test.html
那么为什么带有
DirectoryMatch
的版本找不到该文件?
现在在另一组测试目录中,我上传了以下文件。它们没有被 gzip 压缩:
$ ls -dlU `find test-simple*`
drwxr-xr-x 2 root root 4096 Feb 12 13:51 test-simple-dir
-rw-r--r-- 1 root root 778 Feb 8 14:17 test-simple-dir/test.html.new
drwxr-xr-x 2 root root 4096 Feb 12 13:51 test-simple-match
-rw-r--r-- 1 root root 778 Feb 8 14:17 test-simple-match/test.html.new
我在
/etc/apache2/conf-available/local-settings.conf
中有这些额外的、更简单的设置:
<Directory /var/www/html/test-simple-dir>
LogLevel debug
Header set Cache-Control no-store
RewriteCond "%{REQUEST_FILENAME}.new" -s
RewriteRule ^test\.html$ test.html.new [END]
</Directory>
<DirectoryMatch "^/var/www/html/test-simple-match">
LogLevel debug
Header set Cache-Control no-store
RewriteCond "%{REQUEST_FILENAME}.new" -s
RewriteRule ^test\.html$ test.html.new [END]
</DirectoryMatch>
基本上,如果附加到请求的文件名后的
.new
扩展名作为文件存在,则:
Append `.new`.
再次导航到
test.html
下的 Directory
有效。但在 DirectoryMatch
下它会生成“404 Not Found”。错误日志显示:
[{...}:29:30.136369 2024] [deflate:debug] [pid 919696:tid 281473122804096] mod_deflate.c(869): {...} AH01384: Zlib: Compressed 778 to 404 : URL /test-simple-dir/test.html.new
[{...}:29:47.041233 2024] [core:info] [pid 919696:tid 281473262170496] {...} AH00128: File does not exist: /var/www/html/test-simple-match/test.html
再说一次,为什么带有
DirectoryMatch
的版本找不到该文件?
增加到
LogLevel trace6
产生,在错误日志中:
$ sudo tail /var/log/apache2/error.log
[{...}:03:10.217345 2024] [core:trace3] [pid 938032:tid 281473262170496] request.c(360): [client {...}:27372] request authorized without authentication by access_checker_ex hook: /test-simple-match/test.html
[{...}:03:10.217356 2024] [rewrite:trace3] [pid 938032:tid 281473262170496] mod_rewrite.c(487): [client {...}:27372] {...} - - [{...}/sid#ffff9b6c4208][rid#ffff984370a0/initial] [perdir ^/var/www/html/test-simple-match/] applying pattern '^test\\.html$' to uri '/var/www/html/test-simple-match/test.html'
[{...}:03:10.217362 2024] [rewrite:trace1] [pid 938032:tid 281473262170496] mod_rewrite.c(487): [client {...}:27372] {...} - - [{...}/sid#ffff9b6c4208][rid#ffff984370a0/initial] [perdir ^/var/www/html/test-simple-match/] pass through /var/www/html/test-simple-match/test.html
[{...}:03:10.217376 2024] [core:info] [pid 938032:tid 281473262170496] [client {...}:27372] AH00128: File does not exist: /var/www/html/test-simple-match/test.html
出于诊断目的,在简单的
Directory
和 DirectoryMatch
部分中,我在 RewriteCond
之后立即临时添加了这个 RewriteRule
:
RewriteRule (.*) https://example.com/?path=$1 [R,L]
在
Directory
下,结果是根据需要重定向到 https://example.com/?path=test.html
。
但是在
DirectoryMatch
之下,是为了https://example.com/?path=/var/www/html/test-simple-match/test.html
。换句话说,到绝对文件路径。
那么,在
DirectoryMatch
下,使用RewriteCond
和RewriteRule
指令时如何访问相对文件路径?
Apache 版本:
$ /usr/sbin/apachectl -v
Server version: Apache/2.4.56 (Debian)
Server built: 2023-04-02T03:06:01
Debian 版本:
$ cat /etc/debian_version
11.9
问题的根源在于您的替换(第二个参数)是相对路径。 mod_rewrite 做了一个微妙/脆弱的舞蹈来剥离和删除它认为引导您到达规则的前缀并将其添加回任何相对替换中。 当这是正则表达式时,它不能再根据映射文件名的内部概念添加/删除内容。