使用 mod_proxy_fcgi 和 PATH_INFO 重写 URL 会导致错误 404

使用 mod_proxy_fcgi 和 PATH_INFO 重写 URL 会导致错误 404

我在 Apache 2.4.25 上有一个虚拟主机,其中 PHP-FPM 7.1.4 通过 mod_proxy_fcgi 连接,如下所示:

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /srv/www/example.com

    <Directory /srv/www/example.com>
        AllowOverride All
        Require all granted
    </Directory>

    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    <FilesMatch ".+\.ph(p[3457]?|t|tml)$">
        SetHandler "proxy:unix:/run/php/example.sock|fcgi://localhost"
    </FilesMatch>
</VirtualHost>

大多数应用程序都可以完美地使用此设置,但有一个应用程序使用 PATH_INFO 来提取请求。该应用程序在其 .htaccess 中有类似以下内容:

RewriteEngine On

RewriteCond $1 ^index\.php
RewriteRule ^(.*)$ - [PT,L]

RewriteRule ^(.*)$ index.php/$1 [PT,L]

简单来说,所有不是的都index.php应该作为路径传递给它。访问 URLhttp://example.com/index.php/test工作和显示[PATH_INFO] => /test符合预期,但访问http://example.com/test死于

AH01071: Got error 'Primary script unknown\n'

mod_rewrite 和 mod_proxy_fcgi 的设置LogLevel trace6表明重定向已正确完成,并且正确的路径也传递给了 PHP-FPM。

/index.php/test 的跟踪:

[Sat Apr 29 09:40:41.156316 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] add path info postfix: /srv/www/example.com/index.php -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:40:41.156334 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/index.php/test -> index.php/test
[Sat Apr 29 09:40:41.156348 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'index.php/test'
[Sat Apr 29 09:40:41.156352 2017] [rewrite:trace4] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] RewriteCond: input='index.php/test' pattern='^index\\.php' => matched
[Sat Apr 29 09:40:41.156355 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:40:41.156358 2017] [rewrite:trace1] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141400a0/initial] [perdir /srv/www/example.com/] initial URL equal rewritten URL: /srv/www/example.com/index.php [IGNORING REWRITE]
[Sat Apr 29 09:40:41.156368 2017] [proxy_fcgi:debug] [pid 3014:tid 140574363391744] mod_proxy_fcgi.c(913): [client xx.xx.xx.xx:32622] AH01076: url: fcgi://localhost/srv/www/example.com/index.php proxyname: (null) proxyport: 0
[Sat Apr 29 09:40:41.156371 2017] [proxy_fcgi:debug] [pid 3014:tid 140574363391744] mod_proxy_fcgi.c(920): [client xx.xx.xx.xx:32622] AH01078: serving URL fcgi://localhost/srv/www/example.com/index.php
[Sat Apr 29 09:40:41.156510 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:40:41.156519 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:40:41.156535 2017] [rewrite:trace4] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:40:41.156538 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:40:41.156541 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:40:41.156563 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:40:41.156567 2017] [rewrite:trace3] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:40:41.156571 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:40:41.156575 2017] [rewrite:trace2] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:40:41.156579 2017] [rewrite:trace1] [pid 3014:tid 140574363391744] mod_rewrite.c(477): [client xx.xx.xx.xx:32622] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda1413e0a0/subreq] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:40:41.158640 2017] [proxy_fcgi:trace4] [pid 3014:tid 140574363391744] util_script.c(571): [client xx.xx.xx.xx:32622] Headers from script 'index.php':
[Sat Apr 29 09:40:41.158661 2017] [proxy_fcgi:trace4] [pid 3014:tid 140574363391744] util_script.c(572): [client xx.xx.xx.xx:32622]   Content-type: text/html; charset=UTF-8

/test 的跟踪:

[Sat Apr 29 09:45:01.600510 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600527 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600533 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:45:01.600535 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600537 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600540 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:45:01.600550 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600553 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600556 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:45:01.600560 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141b40a0/initial] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:45:01.600621 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] add path info postfix: /srv/www/example.com/index.php -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600626 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/index.php/test -> index.php/test
[Sat Apr 29 09:45:01.600628 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'index.php/test'
[Sat Apr 29 09:45:01.600643 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] RewriteCond: input='index.php/test' pattern='^index\\.php' => matched
[Sat Apr 29 09:45:01.600646 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600648 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a1a78/initial/redir#1] [perdir /srv/www/example.com/] initial URL equal rewritten URL: /srv/www/example.com/index.php [IGNORING REWRITE]
[Sat Apr 29 09:45:01.600664 2017] [proxy_fcgi:debug] [pid 3013:tid 140574514460416] mod_proxy_fcgi.c(913): [client xx.xx.xx.xx:32639] AH01076: url: fcgi://localhost/srv/www/example.com/index.php proxyname: (null) proxyport: 0
[Sat Apr 29 09:45:01.600666 2017] [proxy_fcgi:debug] [pid 3013:tid 140574514460416] mod_proxy_fcgi.c(920): [client xx.xx.xx.xx:32639] AH01078: serving URL fcgi://localhost/srv/www/example.com/index.php
[Sat Apr 29 09:45:01.600790 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600795 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600799 2017] [rewrite:trace4] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] RewriteCond: input='test' pattern='^index\\.php' => not-matched
[Sat Apr 29 09:45:01.600801 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip per-dir prefix: /srv/www/example.com/test -> test
[Sat Apr 29 09:45:01.600803 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] applying pattern '^(.*)$' to uri 'test'
[Sat Apr 29 09:45:01.600805 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] rewrite 'test' -> 'index.php/test'
[Sat Apr 29 09:45:01.600807 2017] [rewrite:trace3] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] add per-dir prefix: index.php/test -> /srv/www/example.com/index.php/test
[Sat Apr 29 09:45:01.600810 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] forcing '/srv/www/example.com/index.php/test' to get passed through to next API URI-to-filename handler
[Sat Apr 29 09:45:01.600813 2017] [rewrite:trace2] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] strip document_root prefix: /srv/www/example.com/index.php/test -> /index.php/test
[Sat Apr 29 09:45:01.600815 2017] [rewrite:trace1] [pid 3013:tid 140574514460416] mod_rewrite.c(477): [client xx.xx.xx.xx:32639] xx.xx.xx.xx - - [example.com/sid#7fda1635d360][rid#7fda141a30a0/subreq] [perdir /srv/www/example.com/] internal redirect with /index.php/test [INTERNAL REDIRECT]
[Sat Apr 29 09:45:01.602797 2017] [proxy_fcgi:error] [pid 3013:tid 140574514460416] [client xx.xx.xx.xx:32639] AH01071: Got error 'Primary script unknown\n'
[Sat Apr 29 09:45:01.602833 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(571): [client xx.xx.xx.xx:32639] Headers from script 'index.php':
[Sat Apr 29 09:45:01.602839 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(572): [client xx.xx.xx.xx:32639]   Status: 404 Not Found
[Sat Apr 29 09:45:01.602842 2017] [proxy_fcgi:trace4] [pid 3013:tid 140574514460416] util_script.c(572): [client xx.xx.xx.xx:32639]   Content-type: text/html; charset=UTF-8

如何让 Apache 正确重写 URL 并同时传递 PATH_INFO?

笔记:这个问题可能看起来类似于Apache 2.4 + PHP-FPM + ProxyPassMatch但就我而言,我已经在使用SetHandler。问题出在PATH_INFO部分,那里的答案似乎没有解决这个问题。

答案1

经过几天的努力,我捕获并检查了 Apache 和 PHP-FPM 之间发送的 CGI 标头,并使用上述组件的不同版本进行了测试。结果表明,不同版本的 Apache 对SCRIPT_FILENAME变量的设置不同,而 PHP-FPM 中没有考虑到这一点。Apache
2.4.18(我使用的 Ubuntu 16.04 中的默认版本)按如下方式填充变量:

SCRIPT_FILENAME proxy:fcgi://localhost/srv/www/index.php

而 Apache 2.4.25 设置:

SCRIPT_FILENAME /srv/www/index.php

Apache mod_proxy_fcgi 文档提到了一条指令ProxyFCGIBackendType自 Apache 2.4.26 起可用(截至 2017-05-02 尚未发布),默认为“FPM”。描述中有以下注释:

基于此指令的设置而改变的值的一个示例是 SCRIPT_FILENAME。以前使用 mod_proxy_fcgi 时,SCRIPT_FILENAME 以字符串“proxy:fcgi://”作为前缀。此变量是一些通用 FastCGI 应用程序会读取的脚本输入,但 PHP-FPM 会删除前缀,然后记住它正在与 Apache 通信。在 2.4.21 到 2.4.25 中,服务器会自动删除此前缀,从而破坏了 PHP-FPM 在某些情况下检测和与 Apache 交互的能力。

看来我偶然发现了“某种情况”。那么我自己的问题的答案是:不要使用 Apache 2.4.21 到 2.4.25,因为它们包含错误。请使用较低版本或等待修复了错误的较新版本。

相关内容