📄 rewriteguide.html
字号:
<dt>方案:</dt>
<dd>
<div class="example"><pre>
##
## apache-rproxy.conf -- Apache configuration for Reverse Proxy Usage
##
# server type
ServerType standalone
Listen 8000
MinSpareServers 16
StartServers 16
MaxSpareServers 16
MaxClients 16
MaxRequestsPerChild 100
# server operation parameters
KeepAlive on
MaxKeepAliveRequests 100
KeepAliveTimeout 15
Timeout 400
IdentityCheck off
HostnameLookups off
# paths to runtime files
PidFile /path/to/apache-rproxy.pid
LockFile /path/to/apache-rproxy.lock
ErrorLog /path/to/apache-rproxy.elog
CustomLog /path/to/apache-rproxy.dlog "%{%v/%T}t %h -> %{SERVER}e URL: %U"
# unused paths
ServerRoot /tmp
DocumentRoot /tmp
CacheRoot /tmp
RewriteLog /dev/null
TransferLog /dev/null
TypesConfig /dev/null
AccessConfig /dev/null
ResourceConfig /dev/null
# speed up and secure processing
<Directory />
Options -FollowSymLinks -SymLinksIfOwnerMatch
AllowOverride None
</Directory>
# the status page for monitoring the reverse proxy
<Location /apache-rproxy-status>
SetHandler server-status
</Location>
# enable the URL rewriting engine
RewriteEngine on
RewriteLogLevel 0
# define a rewriting map with value-lists where
# mod_rewrite randomly chooses a particular value
RewriteMap server rnd:/path/to/apache-rproxy.conf-servers
# make sure the status page is handled locally
# and make sure no one uses our proxy except ourself
RewriteRule ^/apache-rproxy-status.* - [L]
RewriteRule ^(http|ftp)://.* - [F]
# now choose the possible servers for particular URL types
RewriteRule ^/(.*\.(cgi|shtml))$ to://${server:dynamic}/$1 [S=1]
RewriteRule ^/(.*)$ to://${server:static}/$1
# and delegate the generated URL by passing it
# through the proxy module
RewriteRule ^to://([^/]+)/(.*) http://$1/$2 [E=SERVER:$1,P,L]
# and make really sure all other stuff is forbidden
# when it should survive the above rules...
RewriteRule .* - [F]
# enable the Proxy module without caching
ProxyRequests on
NoCache *
# setup URL reverse mapping for redirect reponses
ProxyPassReverse / http://www1.foo.dom/
ProxyPassReverse / http://www2.foo.dom/
ProxyPassReverse / http://www3.foo.dom/
ProxyPassReverse / http://www4.foo.dom/
ProxyPassReverse / http://www5.foo.dom/
ProxyPassReverse / http://www6.foo.dom/
</pre></div>
<div class="example"><pre>
##
## apache-rproxy.conf-servers -- Apache/mod_rewrite selection table
##
# list of backend servers which serve static
# pages (HTML files and Images, etc.)
static www1.foo.dom|www2.foo.dom|www3.foo.dom|www4.foo.dom
# list of backend servers which serve dynamically
# generated page (CGI programs or mod_perl scripts)
dynamic www5.foo.dom|www6.foo.dom
</pre></div>
</dd>
</dl>
<h3>新的MIME类型,新的服务</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>网上有许多很巧妙的CGI程序,但是用法晦涩,许多网管弃之不用。即使是Apache的MEME类型的动作处理器,也仅仅在CGI程序不需要在其输入中包含特殊URL(<code>PATH_INFO</code>和<code>QUERY_STRINGS</code>)时才很好用。首先,配置一种新的后缀为<code>.scgi</code>(安全CGI)文件类型,其处理器是很常见的<code>cgiwrap</code>程序。问题是:如果使用同类URL规划(见上述),而用户宿主目录中的一个文件的URL是<code>/u/user/foo/bar.scgi</code> ,可是<code>cgiwrap</code>要求的URL的格式是<code>/~user/foo/bar.scgi/</code> ,以下规则解决了这个问题:</p>
<div class="example"><pre>
RewriteRule ^/[uge]/<strong>([^/]+)</strong>/\.www/(.+)\.scgi(.*) ...
... /internal/cgi/user/cgiwrap/~<strong>$1</strong>/$2.scgi$3 [NS,<strong>T=application/x-http-cgi</strong>]
</pre></div>
<p>另外,假设需要使用其他程序:<code>wwwlog</code>(显示<code>access.log</code>中的一个URL子树)和<code>wwwidx</code>(对一个URL子树运行Glimpse),则必须对这些程序提供URL区域作为其操作对象。比如,对<code>/u/user/foo/</code>执行<code>swwidx</code>程序的超链是这样的:</p>
<div class="example"><pre>
/internal/cgi/user/swwidx?i=/u/user/foo/
</pre></div>
<p>其缺点是,必须<strong>同时</strong>硬编码超链中的区域和CGI的路径,如果重组了这个区域,就需要花费大量时间来修改各个超链。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>方案是用一个特殊的新的URL格式,自动拼装CGI参数:</p>
<div class="example"><pre>
RewriteRule ^/([uge])/([^/]+)(/?.*)/\* /internal/cgi/user/wwwidx?i=/$1/$2$3/
RewriteRule ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3
</pre></div>
<p>现在,这个搜索到<code>/u/user/foo/</code>的超链简化成了:</p>
<div class="example"><pre>
HREF="*"
</pre></div>
<p>它会被内部地自动转换为</p>
<div class="example"><pre>
/internal/cgi/user/wwwidx?i=/u/user/foo/
</pre></div>
<p>如此,可以为使用"<code>:log</code>"的超链,拼装出调用CGI程序的参数。</p>
</dd>
</dl>
<h3>从静态到动态</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>如何无缝转换静态页面<code>foo.html</code>为动态的<code>foo.cgi</code> ,而不为浏览器/用户所察觉。</p>
</dd>
<dt>方案:</dt>
<dd>
<p>只须重写此URL为CGI-script ,以强制为可以作为CGI-script运行的正确的MIME类型。如此,对<code>/~quux/foo.html</code>的请求其实会执行<code>/~quux/foo.cgi</code> 。</p>
<div class="example"><pre>
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo\.<strong>html</strong>$ foo.<strong>cgi</strong> [T=<strong>application/x-httpd-cgi</strong>]
</pre></div>
</dd>
</dl>
<h3>传输过程中的内容协商</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>这是一个很难解的功能:动态生成的静态页面,即它应该作为静态页面发送(从文件系统中读出,然后直接发出去),但是如果它丢失了,则由服务器动态生成。这样,可以静态地提供CGI生成的页面,除非有人(或者是一个cronjob)删除了这些静态页面,而且其内容可以得到更新。</p>
</dd>
<dt>方案:</dt>
<dd>以下规则集实现了这个功能:
<div class="example"><pre>
RewriteCond %{REQUEST_FILENAME} <strong>!-s</strong>
RewriteRule ^page\.<strong>html</strong>$ page.<strong>cgi</strong> [T=application/x-httpd-cgi,L]
</pre></div>
<p>这样,如果<code>page.html</code>不存在或者文件大小为null ,则对<code>page.html</code>的请求会导致<code>page.cgi</code>的运行。其中奥妙在于<code>page.cgi</code>是一个将输出写入<code>page.html</code>的(同时也写入<code>STDOUT</code>)的常规的CGI脚本,执行完毕,服务器则将<code>page.html</code>的内容发出。如果网管需要强制更新其内容,只须删除<code>page.html</code>即可(通常由一个cronjob完成)。</p>
</dd>
</dl>
<h3>自动更新的文档</h3>
<dl>
<dt>说明:</dt>
<dd>
<p>建立一个复杂的页面,能够在用编辑器写了一个更新的版本时自动在浏览器上得到刷新,这不是很好吗?这可能吗?</p>
</dd>
<dt>方案:</dt>
<dd>
<p>这是可行的! 这需要综合利用MIME多成分、web服务器的NPH和<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>的URL操控特性。首先,建立一个新的URL特性:对在文件系统中更新时需要刷新的所有URL加上"<code>:refresh</code>" 。</p>
<div class="example"><pre>
RewriteRule ^(/[uge]/[^/]+/?.*):refresh /internal/cgi/apache/nph-refresh?f=$1
</pre></div>
<p>然后,修改URL</p>
<div class="example"><pre>
/u/foo/bar/page.html:refresh
</pre></div>
<p>以内部地操控此URL</p>
<div class="example"><pre>
/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
</pre></div>
<p>接着就是NPH-CGI脚本部分了。虽然,人们常说"将此作为一个练习留给读者",但我还是给出答案了。</p>
<div class="example"><pre>
#!/sw/bin/perl
##
## nph-refresh -- NPH/CGI script for auto refreshing pages
## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##
$| = 1;
# split the QUERY_STRING variable
@pairs = split(/&/, $ENV{'QUERY_STRING'});
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$name =~ tr/A-Z/a-z/;
$name = 'QS_' . $name;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
eval "\$$name = \"$value\"";
}
$QS_s = 1 if ($QS_s eq '');
$QS_n = 3600 if ($QS_n eq '');
if ($QS_f eq '') {
print "HTTP/1.0 200 OK\n";
print "Content-type: text/html\n\n";
print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
exit(0);
}
if (! -f $QS_f) {
print "HTTP/1.0 200 OK\n";
print "Content-type: text/html\n\n";
print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
exit(0);
}
sub print_http_headers_multipart_begin {
print "HTTP/1.0 200 OK\n";
$bound = "ThisRandomString12345";
print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
&print_http_headers_multipart_next;
}
sub print_http_headers_multipart_next {
print "\n--$bound\n";
}
sub print_http_headers_multipart_end {
print "\n--$bound--\n";
}
sub displayhtml {
local($buffer) = @_;
$len = length($buffer);
print "Content-type: text/html\n";
print "Content-length: $len\n\n";
print $buffer;
}
sub readfile {
local($file) = @_;
local(*FP, $size, $buffer, $bytes);
($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
$size = sprintf("%d", $size);
open(FP, "&lt;$file");
$bytes = sysread(FP, $buffer, $size);
close(FP);
return $buffer;
}
$buffer = &readfile($QS_f);
&print_http_headers_multipart_begin;
&displayhtml($buffer);
sub mystat {
local($file) = $_[0];
local($time);
($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
return $mtime;
}
$mtimeL = &mystat($QS_f);
$mtime = $mtime;
for ($n = 0; $n &lt; $QS_n; $n++) {
while (1) {
$mtime = &mystat($QS_f);
if ($mtime ne $mtimeL) {
$mtimeL = $mtime;
sleep(2);
$buffer = &readfile($QS_f);
&print_http_headers_multipart_next;
&displayhtml($buffer);
sleep(5);
$mtimeL = &mystat($QS_f);
last;
}
sleep($QS_s);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -