理解`mod_rewrite`:内部将`foo.txt`重定向到`foo.txt.cgi`,其中`foo.txt`不存在?

时间:2015-03-16 22:54:40

标签: apache .htaccess mod-rewrite cgi

我的目标是从目录中提供.txt个文件,但如果某个.txt文件不存在,我想执行 内部 < / strong>重定向到类似名称的.txt.cgi脚本,如果存在这样的脚本。这个问题涉及为什么一种方法似乎有效,但两种替代方法 工作。

我有以下目录结构(即,作为/var/www中的某个子目录或等效目录):

% ls -ARl rewritecgi
total 0
drwxr-sr-x  2 posita  posita  170 Mar 16 14:36 test1
drwxr-sr-x  2 posita  posita  170 Mar 16 14:38 test2
drwxr-sr-x  2 posita  posita  170 Mar 16 14:38 test3

rewritecgi/test1:
total 24
-rw-r--r--  1 posita  posita  288 Mar 16 14:36 .htaccess
-rw-r--r--  1 posita  posita   28 Mar 16 14:34 other.txt
-rwxr-xr-x  1 posita  posita  143 Mar 16 14:20 test.txt.cgi

rewritecgi/test2:
total 24
-rw-r--r--  1 posita  posita  301 Mar 16 14:38 .htaccess
-rw-r--r--  1 posita  posita   28 Mar 16 14:34 other.txt
-rwxr-xr-x  1 posita  posita  143 Mar 16 14:19 test.txt.cgi

rewritecgi/test3:
total 24
-rw-r--r--  1 posita  posita  288 Mar 16 14:38 .htaccess
-rw-r--r--  1 posita  posita   28 Mar 16 14:34 other.txt
-rwxr-xr-x  1 posita  posita  143 Mar 16 14:20 test.txt.cgi
每个other.txt子目录中的

test{1,2,3}只是一个普通的旧文本文件。

每个test.txt.cgi子目录中的

test{1,2,3}包含:

#!/usr/bin/env sh
cat <<EOF
Content-Type: text/plain

Hi! I'm \`${0}\`!
EOF

test1/.htaccess如下:

Options +FollowSymlinks -Indexes -MultiViews
AddHandler cgi-script .cgi
RewriteEngine on
RewriteBase /~posita/rewritecgi/test1/
<Files ~ "\.cgi$">
    Options +ExecCGI
</Files>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule "^(.*\.txt)$" "$1.cgi"

test2/.htaccesstest1/.htaccess相同,但会将+ExecCGI移至顶层(如果我使用403,我会获得<Files>)并添加[H=cgi-script]的{​​{1}}标记:

RewriteRule

mod_rewrite documentation for the H flag表明这应该有用。

Options +ExecCGI +FollowSymlinks -Indexes -MultiViews AddHandler cgi-script .cgi RewriteEngine on RewriteBase /~posita/rewritecgi/test2/ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule "^(.*\.txt)$" "$1.cgi" [H=cgi-script] test3/.htaccess相同,但启用test1/.htaccess选项:

+MultiViews

不出所料,所有Options +FollowSymlinks -Indexes +MultiViews AddHandler cgi-script .cgi RewriteEngine on RewriteBase /~posita/rewritecgi/test3/ <Files ~ "\.cgi$"> Options +ExecCGI </Files> RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule "^(.*\.txt)$" "$1.cgi" 个文件都没有问题解决:

other.txt

显式调用时,所有三个% for i in 1 2 3 ; do echo "----> ${i} <----" ; curl --location --post30{1,2,3} --silent "http://localhost/~posita/rewritecgi/test${i}/other.txt" ; done ----> 1 <---- Just a plain old text file. ----> 2 <---- Just a plain old text file. ----> 3 <---- Just a plain old text file. 脚本都正常运行:

test.txt.cgi

但是,只有% for i in 1 2 3 ; do echo "----> ${i} <----" ; curl --location --post30{1,2,3} --silent "http://localhost/~posita/rewritecgi/test${i}/test.txt.cgi" ; done ----> 1 <---- Hi! I'm `/.../posita/public_html/rewritecgi/test1/test.txt.cgi`! ----> 2 <---- Hi! I'm `/.../posita/public_html/rewritecgi/test2/test.txt.cgi`! ----> 3 <---- Hi! I'm `/.../posita/public_html/rewritecgi/test3/test.txt.cgi`! 重定向到CGI:

http://localhost/~posita/rewritecgi/test1/test.txt

使用% for i in 1 2 3 ; do echo "----> ${i} <----" ; curl --location --post30{1,2,3} --silent "http://localhost/~posita/rewritecgi/test${i}/test.txt" ; done ----> 1 <---- Hi! I'm `/.../posita/public_html/rewritecgi/test1/test.txt.cgi`! ----> 2 <---- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /~posita/rewritecgi/test2/test.txt was not found on this server.</p> </body></html> ----> 3 <---- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL /~posita/rewritecgi/test3/test.txt was not found on this server.</p> </body></html> ,我收到RewriteLogLevel 9的以下日志消息:

http://localhost/~posita/rewritecgi/test2/test.txt

对于==> /var/log/apache2/rewrite_log <== 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (3) [perdir /.../posita/public_html/rewritecgi/test2/] strip per-dir prefix: /.../posita/public_html/rewritecgi/test2/test.txt -> test.txt 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (3) [perdir /.../posita/public_html/rewritecgi/test2/] applying pattern '^(.*\\.txt)$' to uri 'test.txt' 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (4) [perdir /.../posita/public_html/rewritecgi/test2/] RewriteCond: input='/.../posita/public_html/rewritecgi/test2/test.txt' pattern='!-f' => matched 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (4) [perdir /.../posita/public_html/rewritecgi/test2/] RewriteCond: input='/.../posita/public_html/rewritecgi/test2/test.txt' pattern='!-d' => matched 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (2) [perdir /.../posita/public_html/rewritecgi/test2/] rewrite 'test.txt' -> 'test.txt.cgi' 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (3) [perdir /.../posita/public_html/rewritecgi/test2/] add per-dir prefix: test.txt.cgi -> /.../posita/public_html/rewritecgi/test2/test.txt.cgi 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (2) [perdir /.../posita/public_html/rewritecgi/test2/] remember /.../posita/public_html/rewritecgi/test2/test.txt.cgi to have Content-handler 'cgi-script' 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (2) [perdir /.../posita/public_html/rewritecgi/test2/] trying to replace prefix /.../posita/public_html/rewritecgi/test2/ with /~posita/rewritecgi/test2/ 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (5) strip matching prefix: /.../posita/public_html/rewritecgi/test2/test.txt.cgi -> test.txt.cgi 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (4) add subst prefix: test.txt.cgi -> /~posita/rewritecgi/test2/test.txt.cgi 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (1) [perdir /.../posita/public_html/rewritecgi/test2/] internal redirect with /~posita/rewritecgi/test2/test.txt.cgi [INTERNAL REDIRECT] 127.0.0.1 - - [16/Mar/2015:15:30:42 --0700] [localhost/sid#7fb378812308][rid#7fb3788abea0/initial] (1) force filename redirect:/~posita/rewritecgi/test2/test.txt.cgi to have the Content-handler 'cgi-script' ==> /var/log/apache2/access_log <== 127.0.0.1 - - [16/Mar/2015:15:30:42 -0700] "GET /~posita/rewritecgi/test2/test.txt HTTP/1.1" 404 229 ==> /var/log/apache2/error_log <== [Mon Mar 16 15:30:42 2015] [error] [client 127.0.0.1] script not found or unable to stat: redirect:/~posita/rewritecgi/test2/test.txt.cgi

http://localhost/~posita/rewritecgi/test3/test.txt

那是什么给出的?为什么添加==> /var/log/apache2/rewrite_log <== 127.0.0.1 - - [16/Mar/2015:15:35:47 --0700] [localhost/sid#7fb378812308][rid#7fb37889aea0/subreq] (3) [perdir /.../posita/public_html/rewritecgi/test3/] strip per-dir prefix: /.../posita/public_html/rewritecgi/test3/test.txt.cgi -> test.txt.cgi 127.0.0.1 - - [16/Mar/2015:15:35:47 --0700] [localhost/sid#7fb378812308][rid#7fb37889aea0/subreq] (3) [perdir /.../posita/public_html/rewritecgi/test3/] applying pattern '^(.*\\.txt)$' to uri 'test.txt.cgi' 127.0.0.1 - - [16/Mar/2015:15:35:47 --0700] [localhost/sid#7fb378812308][rid#7fb37889aea0/subreq] (1) [perdir /.../posita/public_html/rewritecgi/test3/] pass through /.../posita/public_html/rewritecgi/test3/test.txt.cgi ==> /var/log/apache2/access_log <== 127.0.0.1 - - [16/Mar/2015:15:35:47 -0700] "GET /~posita/rewritecgi/test3/test.txt HTTP/1.1" 404 229 ==> /var/log/apache2/error_log <== [Mon Mar 16 15:35:47 2015] [error] [client 127.0.0.1] Negotiation: discovered file(s) matching request: /.../posita/public_html/rewritecgi/test3/test.txt (None could be negotiated). 会导致[H=cgi-script]不调用CGI?对于test2,为什么启用test3规避+MultiViews?我知道mod_rewrite is voodoo,但我确实想了解这些情况之间的细微差别。

1 个答案:

答案 0 :(得分:2)

如果在当前目录中找不到文件,则会在其他目录中查找文件。这意味着它找到结果并不局限于同一目录,而不是它绕过mod_rewrite。它使用mod_negotiation。使用Multiviews选项,服务器可以根据模式选择要选择的最佳文件。这不是你在使用.htaccess和mod_rewrite时所处的情况。我从不使用它。

我注意到你的.htaccess里有RewriteConds。它们不是必需的。我没有它就让它工作。你在.htaccess中指定的越多,你可以遇到的问题就越多。 (重写可能确实是伏都教。) 我在没有这些条件的情况下创建了一个.htaccess文件,它起作用了:

Options +ExecCGI
AddHandler cgi-script .cgi
RewriteEngine on
RewriteBase /StackoverflowQuestions/tests/cgi/
RewriteRule ^(.*)\.txt$ $1.cgi [L]

这足以让它发挥作用。现在,RewriteRule只解析了相同的文件名,而不是文件名+扩展名。 在处理程序标签[H ...]中,您需要指定cgi文件的mime类型。那是application / x-httpd-cgi,而不是cgi-script。但是在使用AddHandler时不需要指定H标志。