我正在将一个大图像目录从 HTTP 服务器移动到另一个服务器,但无法更改任何配置。
我希望我的用户甚至不会想到有移动正在进行。所以我想在两台服务器前面添加一个配置为反向代理的 Apache httpd 服务器。
当在目标中找不到资源时,此反向代理应尝试在原始服务器中获取它。
有没有办法使用 mod_rewrite 或某些标准 Apache httpd 模块来做到这一点?
资源不在前端服务器上,而是在两台后端服务器上。
答案1
要检查 RewriteCond 中的远程资源,您可以使用以下命令:
'-U'(是现有 URL,通过子请求)检查 TestString 是否是有效 URL,可通过该路径的所有服务器当前配置的访问控制进行访问。这使用内部子请求进行检查,因此请谨慎使用 - 它可能会影响服务器的性能!
我个人从未使用过它。但它的工作原理类似于测试文件是否存在等。
然后您可以拥有一个代理请求的 RewriteRule([P] 选项)。
答案2
我已经使用 Apache httpd 2.2 实现了反向代理,但仅使用 apache 指令无法实现。因此我不得不使用一个简单的 PHP 脚本来检查远程 URL 是否存在。
当有新请求到来时,它会检查服务器 A 上是否存在当前路径,如果成功找到,它会在同一台服务器上反向代理该请求。另一方面,如果在服务器 A 上找不到请求的路径,它会在服务器 B 上实施重写规则反向代理。
我使用了RewriteMap
withMapType
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]
接下来是有趣而棘手的部分。这是url_exists.php
由 Apache 执行的脚本。它等待标准输入流并写入标准输出。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";
error_log($line. " ".$str);
echo $str."\n";
} else {
error_log('empty line!');
}
}