我已经为这个问题苦思冥想很久了。
我有一个简单的配置,使用 Apache 的 proxypass 规则,我想在使用“catchall”规则将所有流量重定向到本地节点服务器之前提供一个排除列表。
设置如下:
ProxyPass /contact-us !
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
上述配置的结果是/contact-us
将发送到节点(localhost:3000
),根据我对文档的理解,它应该被忽略。如果我为设置了目的地,/contact-us
那么请求就会得到正确处理,并返回代理内容。
我是不是漏掉了什么?将 catchall( /
) 添加到规则集会改变行为吗?
编辑:添加其余文件以供参考
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName dev.site.com
ServerAdmin [email protected]
ProxyPass /contact-us !
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
DocumentRoot /var/www/site/public
<Directory /var/www/site/public>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
<IfModule mod_headers.c>
SetEnvIf Origin "^http(s)?://(.+\.)?(dev\.site\.com)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
Header always set Access-Control-Allow-Credentials true env=origin_is
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/dev.site.com-error.log
CustomLog ${APACHE_LOG_DIR}/dev.site.com-access.log combined
SSLCertificateFile /etc/letsencrypt/live/dev.site.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/dev.site.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
答案1
我发现了我的问题并且你是对的@HBruijn。
我在虚拟主机上运行 Laravel 框架,这意味着请求被直接/index.php
发送到路由,因此在第一条规则成功后(/contact-us !
),请求被重写为/index.php
然后在捕获所有规则中被代理。
我可以为 ( /index.php
) 添加排除规则,以及以下 Fpm 请求(参见下面的日志)来解决我的问题。此解决方案可能并不适合所有人。
感谢 @yunzen 的评论,我才得以解开这一谜团 -https://serverfault.com/a/895673,通过添加LogLevel error proxy:trace5
我能够看到以下内容:
[Mon Mar 04 04:39:56.876129 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/contact-us' against prefix '/index.php' for proxying
[Mon Mar 04 04:39:56.876170 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/contact-us' against prefix '/contact-us' for proxying
[Mon Mar 04 04:39:56.876174 2019] [proxy:trace1] [pid 5564] mod_proxy.c(736): [client 220.244.99.86:51059] AH03463: proxying is explicitly disabled for URI path '/contact-us'; declining
[Mon Mar 04 04:39:56.876880 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/index.php' against prefix '/index.php' for proxying
[Mon Mar 04 04:39:56.876890 2019] [proxy:trace1] [pid 5564] mod_proxy.c(736): [client 220.244.99.86:51059] AH03463: proxying is explicitly disabled for URI path '/index.php'; declining
[Mon Mar 04 04:39:56.876936 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/php72-fcgi-www/index.php' against prefix '/index.php' for proxying
请注意此单个请求引起的上下文变化。
答案2
根据 Apache(仅限 2.4.26 及更高版本)文档中的一些注释,可以使用no-proxy
环境变量进行代理排除。
然而,当您需要内部重写来为您的排除页面提供服务时,情况就会变得很糟糕,因为 ProxyPass 排除和仅no-proxy
基于 REQUEST_URI 设置变量没有效果,因为 REQUEST_URI 在内部重写之后发生了变化,并且 ProxyPass 再次被评估,并且环境变量仅可见为REDIRECT_no-proxy
不可见no-proxy
。
我们可以在这里使用一些小技巧,而且会起作用:
RewriteEngine on
RewriteRule ^/contact-us$ - [E=no-proxy:1]
RewriteCond %{ENV:REDIRECT_no-proxy} .+
RewriteRule .* - [E=no-proxy:1]
如果您将其放在 Virtual Host 部分,它将起作用。如果您将其放在 Directory 部分,则不会起作用,因为此时 ProxyPass 已经生效。