Apache:如果外部资源存在,只需重写

时间:2012-10-23 12:36:35

标签: mod-rewrite url-rewriting apache2 apache reverse-proxy

我使用Apache作为反向代理。专用服务器本身没有Web内容。如果客户端请求本地Apache服务器上的资源,Apache应确定该资源存在于哪个远程(代理)服务器上,并对该服务器执行代理重写。

一个片段(当前不起作用)应该演示,我会做什么:

RewriteCond               http://200.202.204.11:3000%{REQUEST_URI}    -U
RewriteRule     ^(.*)$    http://200.202.204.11:3000$1                [P]

我放弃了我的其余配置(ProxyPass,ProxyPassReverse,其他RewriteCond,......)来专注于我的问题:

如何在重写之前检查外部资源是否存在?

RewriteCond的 -U 选项返回al。 -F 选项返回alwas false。我的意图是否有可行的解决方案?

2 个答案:

答案 0 :(得分:0)

在寻找解决方案数周之后,我得出结论:如果存在外部资源,则没有可靠的RewriteRule。

如果您通过子域在反向代理服务器后面解决您的服务,那么您会好得多。例如。 'gitlab.youdomain.net'如果你想在你的反向代理后面的gitlab服务器上解决一个资源。因此,如果资源位于gitlab服务器的根目录“/”中,则反向代理不会混淆。

答案 1 :(得分:0)

我有同样的问题但是,据我所知,我得到了相同的结果:不可能只使用Apache httpd指令(至少使用2.2版本)。
在我的解决方案中,我使用RewriteMap和PHP脚本来检查外部资源是否存在。

在此示例中,当新请求到来时,RewriteMap会检查服务器A上是否存在请求的路径,如果成功找到,则会在同一服务器上反向代理请求。 另一方面,如果在服务器A上找不到请求的路径,它会实现重写规则以反向代理服务器B上的请求。

如上所述,我使用了RewriteMap MapType prg:和PHP脚本。 这里有Apache指令:

# Please pay attention to RewriteLock
# this directive must be defined in server config context
RewriteLock /tmp/if_url_exists.lock

RewriteEngine On

ProxyPreserveHost Off
ProxyRequests Off

RewriteMap  url_exists "prg:/usr/bin/php /opt/local/scripts/url_exists.php"
RewriteCond ${url_exists:http://serverA%{REQUEST_URI}}   >0
RewriteRule .            http://serverA%{REQUEST_URI} [P,L]

RewriteRule .            http://serverB%{REQUEST_URI} [P,L]

这是一个有趣且棘手的部分。 这是由Apache执行的url_exists.php脚本。它正在等待标准输入流并写入标准输出。 如果找到并可读资源,此脚本将返回1,否则为0。 它很轻,即使它只使用HEAD方法实现HTTP请求。

<?php

function check_if_url_exists($line) {
    $curl_inst = curl_init($line);
    curl_setopt( $curl_inst, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt( $curl_inst, CURLOPT_LOW_SPEED_LIMIT, 1);
    curl_setopt( $curl_inst, CURLOPT_LOW_SPEED_TIME, 180);
    curl_setopt( $curl_inst, CURLOPT_HEADER, true);
    curl_setopt( $curl_inst, CURLOPT_FAILONERROR, true);
    // Exclude the body from the output and request method is set to HEAD.
    curl_setopt( $curl_inst, CURLOPT_NOBODY, true);
    curl_setopt( $curl_inst, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt( $curl_inst, CURLOPT_RETURNTRANSFER, true);
    $raw = curl_exec($curl_inst);
    curl_close($curl_inst);
    return ($raw != false) ? true : false;
}

set_time_limit(0);
$keyboard = fopen("php://stdin","r");

while (true) {
    $line = trim(fgets($keyboard));
    if (!empty($line)) {
        $str = (check_if_url_exists($line)) ? "1" : "0";
        echo $str."\n";
    }
}