好的,找到了(另见一些相关的帖子Debugging Apache2 RewriteRule (with headers)?)
所以,我能找到的唯一有用的是Using RewriteMap - Apache HTTP Server Version 2.4。现在,由于我使用的是 Apache 的 Windows 版本,它变得有些棘手 - 但仍然可行。
网上有很多关于如何使它工作的信息;重要信息在这里找到RewriteMap prg: issue on Windows - Apache Web Server forum at WebmasterWorld - By Pubcon:
如果“RewriteEngine On”指令在 OUTSIDE 之外,则 RewriteMap 程序启动,如下所示
在我的例子中,当且仅当 RewriteMap 指令为 OUTSIDE <Location> 时,RewriteMap 程序才会启动;并且“RewriteEngine On”在 OUTSIDE <Location> - 在任何其他情况下,程序都不会启动。
我们应该注意的第二件事是,来自https://httpd.apache.org/docs/2.4/rewrite/rewritemap.html:
当使用 prg 的 MapType 时,MapSource 是一个文件系统路径
将提供映射行为的可执行程序。这
可以是编译后的二进制文件,也可以是解释语言的程序
例如 Perl 或 Python。
这个程序启动一次,当Apache HTTP Server启动时,
然后通过 STDIN 和 STDOUT 与重写引擎通信。
也就是说,对于每个映射函数查找,它需要一个参数
STDIN,并且应该返回一个换行符终止的响应字符串
标准输出。如果没有对应的lookup值,map程序
应该返回四个字符的字符串“NULL”来表明这一点。
如果外部重写程序定义在
没有将 RewriteEngine 设置为 on 的上下文。
换句话说 - 使用的程序必须打开它的 STDIN 和 STDOUT - AND 它必须 连续阻塞;即使你想做的是perl -i -pe's/SEARCH/REPLACE/',那种程序读取输入、处理、提供输出、然后退出——所以在这种情况下,它对我们没有任何好处。
因此,根据 rewritemap.html 中给出的示例 - 这是一个 Perl 脚本,它用 %2F 替换正斜杠 (/),同时连续阻塞,称为 convslash.pl,保存在 C:\bin\Apache24\bin\ 中
#!C:/msys64/usr/bin/perl.exe
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
s|/|%2F|g; # Replace / with %2F
print $_;
}
然后,我将其添加到我的httpd.conf:
# the below starts and runs ONLY if RewriteEngine On is outside of <Location>; also a cmd.exe window is started (plus another for perl!)
#RewriteMap doprg "prg:c:/msys64/usr/bin/perl.exe c:/bin/Apache24/bin/dash2under.pl"
# the below is slightly better - only one cmd.exe window is started:
RewriteMap doprg "prg:c:/Windows/System32/cmd.exe /c start /b c:/msys64/usr/bin/perl.exe c:/bin/Apache24/bin/convslash.pl"
# we MUST have RewriteEngine On here, outside of location - otherwise the RewriteMap program will never start:
RewriteEngine On
<Location /subfold/dl>
Options -Multiviews
RewriteEngine On
RewriteOptions Inherit
# first RewriteCond - this is just so we can capture the relevant parts into environment variables:
RewriteCond %{REQUEST_URI} ^/subfold/dl/(.*)/(.*)$
RewriteRule ^ - [E=ONE:%1,E=TWO:%2,NE]
# the above RewriteRule does not rewrite - but passes the input string further;
# so here, let's have another such RewriteRule - just so we can set our processed/desired output to a variable, which we can "print" via headers:
RewriteRule ^ - [E=MODDED:subfold/dl/${doprg:%{ENV:ONE}}/%{ENV:TWO},NE]
# the original URL will finally pass through unmodified to the "file handler" which will attempt to map it to the filesystem, it will fail, and return 404.
# the below headers should be returned along with that 404:
Header always set X-ONE "%{ONE}e"
Header always set X-TWO "%{TWO}e"
Header always set X-INPUT "%{INPUT}e"
Header always set X-MODDED "%{MODDED}e"
Header always set X-REQ "expr=%{REQUEST_URI}"
</Location>
所以,现在我在本地启动服务器 (./bin/httpd.exe),为了测试这一点,我使用 curl 发出请求:
$ curl -IkL http://127.0.0.1/subfold/dl/my/spec/test.html
HTTP/1.1 404 Not Found
Date: Mon, 18 Oct 2021 17:08:11 GMT
Server: Apache/2.4.46 (Win32) OpenSSL/1.1.1j
X-ONE: my/spec
X-TWO: test.html
X-INPUT: (null)
X-MODDED: subfold/dl/my%2Fspec/test.html
X-REQ: /subfold/dl/my/spec/test.html
Content-Type: text/html; charset=iso-8859-1
...最后,我们可以在 X-MODDED 标头中看到,确实我们设法仅替换了重写 URL 中的子字符串 ...
好吧,我希望以某种方式记录下来,而且我不必浪费 8 个小时的时间来解决这个问题 - 但谁在乎呢,几年后将会有新的服务器,其中所有这将是无关紧要的,因此将不得不浪费更多的时间——所有这些都是为了提供更多的废话、广告和间谍活动。