提供跑道鋪面、全透水鋪面、環氧樹脂地坪工程服務
多年施工經驗,歡迎洽詢規劃!
搜尋引擎低預算卻能賦予家新風格
室內裝潢評價最高 獨特減法美學設計,

首頁  •  j2h 論壇 • 程式設計討論     • 

Apache的Module rewrite 技術實現動態頁面

房東:西門不吹雪
發表時間:2007-01-31


Apache的Module rewrite 技術實現動態頁面靜態化
誰能把PHPWind 也從寫了???或者官方能不能開通這樣的,就是和無圖版還有博客的一樣這個功能,但是並非無圖版使用,而是預設的程式也增加這個重寫支援 靜態目錄部署


RewriteEngine On
RewriteRule ^(.*)/simple/([a-z0-9\_]+\.html)$ $1/simple/index.php?$2


非常需要,這樣可以更方便的讓搜索引擎搜索到,而且大部分用戶訪問就是預設的界面,凡是會員很少有人訪問無圖版的。


下面轉載一個PHPBB MOD for Google 完全解決方案

讓Google為動態頁面的站點服務

Internet上網站數量的增多,網站的宣傳越來越多地倚賴搜索引擎的搜索結果,怎樣讓搜索引擎更好地為站點服務與提升站點的訪問量有著非常密切的關係。搜索引擎並非是上帝的贈送給Internet產物,搜索引 擎其本身既是站點,同時也是由各個程式來建設的。而各種搜索引擎一般都使用一種稱為搜索引擎機器人的技術,這種機器人會根據一定規則的在Internet上訪問站點,並把有價值的頁面收集到搜索引擎的緩存數據庫儲存。一旦有用戶來搜索,那麼搜索引擎會直接在其緩存中搜索結果,並將結果報給用戶。


搜索機器人的查找規則比較複雜,但是其中有一個很重要的規則,就是搜索機器人對靜態頁面的處理能力要強於動態頁面。一般情況下搜索機器人簡單的把靜態頁面理解為擴展名成.html或者.htm的頁面,而將擴展名是.ASP、.PHP及.CGI的頁面理解成動態頁面。換言之如果一個站點都是.html頁面,那麼它被搜索引擎全文搜到的可能性就要比.PHP的頁面高幾個數量級,當然因此而來的訪問量也會高出很多。


如何把自己站點的內容全都靜態頁面化,最簡單的做法自然是每個頁面都用頁面設計軟體直接作成靜態頁面,這對小型站點不是難事,但是對頁面總數上萬的大中型站點,都用手工的靜態頁面設計就會帶來高昂的成本和儲存、修改上的困難。在這種情況下,資金雄濃的大網站會採用能在後台生成.html檔案的內容管理(CMS)系統管理。無論是手工做的.html檔案,還是後台生成的.html檔案,都能實現真正意義上的靜態頁面。


但仍有相當數量的中型站點採用動態發布的CMS系統,動態系統對網頁的更新效率很高,可在後台發排的同時在前台顯示,缺點是要消耗相當量的伺服器資源,同時得到一堆擴展名為.ASP.PHP的頁面。要完全替換CMS系統並不容易,而且具有靜態頁面後台生成功能的成熟CMS系統價格都很高昂。


動態CMS系統有無簡單獲取.html檔案擴展名的方法?當然有,採用URL重寫轉向功能。


對URL重寫轉向的支援,在Apache伺服器上由一非缺省模塊(mod_rewrite)來完成,這個模塊的功能很強大,同時也很煩瑣。而在IIS下也同樣有類似的模塊,分別是ISAPI REWRITE及IIS REWRITE。無論是在Apache下還是在IIS下,重寫轉向的語法都基於正則表達式,只有少量的不同。當然對一般的應用,沒必要把所有手冊和說明文檔翻熟,下面以一個虛擬的http://www.1234567.com動態站點為例介紹一些簡單的方法,讀者可以根據自己網站的情況做調整。


網路欄目︰http://www.1234567.com/content.asp?sort=3

在IIS的安裝isapirewrite的情況下只須設定︰RewriteRule /content/(\d+)\.html /content\.asp\?sort=$1 [N,I]

這樣就將︰/content/3.html 這樣的請求映射成為/content.asp?sort=3

然後透過︰http://www.1234567.com/content/3.html 同樣能訪問到剛才的頁面。

另一個更通用的能將所有的動態頁面做參數映射的表達式是︰

RewriteRule (.*?\.php)(\?[^/]*)?/([^/]*)/([^/]*)(.+?)? $1(?2$2&:\?)$3=$4?5$5: [N,I]

這樣就把http://www.my123.com/foo.php?a=A&b=B&c=C表現成http://www.my123.com/foo.php/a/A/b/B/c/C。


當然用URL重寫轉向而得的.html的URL實質上還是個動態頁面,只是搜索引擎上的機器人及瀏覽器上的鏈接與正常的靜態頁面一摸一樣,URL對用戶的親和度非常高。即便是在用模塊模式營運的Apache下,這樣或多或少都會有一些性能上的損失。同時如果真的把論壇這種更新非常快的內容也讓Google搜索進去並不能方便用戶,有時候還會帶來很多負面影響。所以URL重寫轉向最合適的用途是一些中小型CMS動態頁面發布平台,以便讓搜索引擎能記錄下主頁內容從而讓更多的人能搜索到。



-----------------------------------------------------------------------------

PHPBB MOD for Google 完全解決方案

作者︰Trotter
郵箱︰[email protected]
出處︰www.gbunix.com

轉載請保持文檔完整,注明出處。

前言

  隨著互聯網上的內容以驚人速度的增長也越來越突出了搜索引擎的重要性,如果網站想更好地被搜索引擎收錄,網站設計除了面向用戶友好(User Friendly)外,搜索引擎友好(Search Engine Friendly)的設計也是非常重要的。進入搜索引擎的頁面內容越多,則被用戶用不同的關鍵詞找到的幾率越大。不得不承認,將動態網頁鏈接rewriting成靜態鏈接是最保險和穩定的面向搜索引擎優化模式。該方案就是針對phpBB論壇系統的URL重定向提出的。

解決方案

  URL重定向從技術上將,目前可以透過兩種模式實現,一種是基於URL rewrite,另一種是基於PATH_INFO。例如http://www.gbunix.com/bbs/ftopic102.html就是基於rewrite實現的,而http://www.gbunix.com/article/article.php/515是基於PATH_INFO實現的。

  針對PHPBB論壇的改造,我們分別就這兩種技術分別介紹。

一.使用rewrite技術實現︰

修改phpBB代碼︰

打開/includes/page_header.php檔案,

搜索代碼︰

//
// Generate logged in/logged out status
//

之前加︰

ob_start();
function replace_for_mod_rewrite(&$s)
{
$urlin =
array(
"'(? "'(? "'(? "'(? "'(? "'(? "'(? "'(? "'(? "'(? "'(? );
$urlout = array(
"viewforum\\1-\\2-\\3.html",
"forum\\1.html",
"forum\\1.html",
"ptopic\\1.html",
"ntopic\\1.html",
"ftopic\\1-\\2-\\3-\\4.html",
"ftopic\\1.html",
"ftopic\\1-\\2.html",
"ftopic\\1.html",
"sutra\\1.html",
"sutra\\1.html",
);
$s = preg_replace($urlin, $urlout, $s);
return $s;
}

打開/includes/page_tail.php檔案,

搜索代碼︰

$db->sql_close();

之後加︰

$contents = ob_get_contents();
ob_end_clean();
echo replace_for_mod_rewrite($contents);
global $dbg_starttime;

如果你的phpBB是2.06版本,打開includes/functions.php檔案,

搜索代碼︰

if (!empty($db))
{
$db->sql_close();
}

之後加︰

if (stristr($url, 'http://')) {
header('Location: ' . $url);
exit;
}

最後在bbs目錄下建立.htaccess 檔案,檔案內容為︰

RewriteEngine On
RewriteRule ^forums.* index.php
RewriteRule ^forum([0-9]*).* viewforum.php?f=$1&mark=topic
RewriteRule ^viewforum([0-9]*)-([0-9]*)-([0-9]*).* viewforum.php?f=$1&topicdays=$2&start=$3
RewriteRule ^forum([0-9]*).* viewforum.php?f=$1
RewriteRule ^ptopic([0-9]*).* viewtopic.php?t=$1&view=previous
RewriteRule ^ntopic([0-9]*).* viewtopic.php?t=$1&view=next
RewriteRule ^ftopic([0-9]*)-([0-9]*)-([a-zA-Z]*)-([0-9]*).* viewtopic.php?t=$1&postdays=$2&postorder=$3&start=$4
RewriteRule ^ftopic([0-9]*)-([0-9]*).* viewtopic.php?t=$1&start=$2
RewriteRule ^ftopic([0-9]*).* viewtopic.php?t=$1
RewriteRule ^ftopic([0-9]*).html viewtopic.php?t=$1&start=$2&postdays=$3&postorder=$4&highlight=$5
RewriteRule ^sutra([0-9]*).* viewtopic.php?p=$1

如果你的伺服器不支援.htaccess,請打開httpd.conf檔案,編輯你的虛擬主機部分,如下︰


ServerAdmin [email protected]
DocumentRoot /home1/ftp/trotter/www
ServerName www.gbunix.com
RewriteEngine On
RewriteRule ^/bbs/forums.* /bbs/index.php
RewriteRule ^/bbs/forum([0-9]*).* /bbs/viewforum.php?f=$1&mark=topic
RewriteRule ^/bbs/viewforum([0-9]*)-([0-9]*)-([0-9]*).* /bbs/viewforum.php?f=$1&topicdays=$2&start=$3
RewriteRule ^/bbs/forum([0-9]*).* /bbs/viewforum.php?f=$1
RewriteRule ^/bbs/ptopic([0-9]*).* /bbs/viewtopic.php?t=$1&view=previous
RewriteRule ^/bbs/ntopic([0-9]*).* /bbs/viewtopic.php?t=$1&view=next
RewriteRule ^/bbs/ftopic([0-9]*)-([0-9]*)-([a-zA-Z]*)-([0-9]*).* /bbs/viewtopic.php?t=$1&postdays=$2&postorder=$3&start=$4
RewriteRule ^/bbs/ftopic([0-9]*)-([0-9]*).* /bbs/viewtopic.php?t=$1&start=$2
RewriteRule ^/bbs/ftopic([0-9]*).* /bbs/viewtopic.php?t=$1
RewriteRule ^/bbs/ftopic([0-9]*).html /bbs/viewtopic.php?t=$1&start=$2&postdays=$3&postorder=$4&highlight=$5
RewriteRule ^/bbs/sutra([0-9]*).* /bbs/viewtopic.php?p=$1
ErrorLog logs/gbunix.com-error_log
CustomLog logs/gbunix.com-access_log combined


如果你用的不是虛擬主機,將RewriteRule部分代碼放到httpd.conf檔案最後就可以。

注意︰非常重要的一點,為了系統的安全,請在bbs發布目錄下建立robots.txt檔案,檔案內容如下︰

Disallow: /your-forum-folder/sutra*.html$
Disallow: /your-forum-folder/ptopic*.html$
Disallow: /your-forum-folder/ntopic*.html$
Disallow: /your-forum-folder/ftopic*asc*.html$

給apache安裝mod_rewrite模塊

  如果你的伺服器apache還沒有安裝,那很簡單,在編譯apache時將mod_rewrite模塊編譯進去就可以,相關文檔可以在www.gbunix.com中找到。如果你的apache已經安裝好了,現下只想編譯出mod_rewrite.so模塊,在apache中進行加載,下面我們就介紹這個方法。

以Solaris作業系統進行舉例︰

# PATH=/usr/local/bin:/usr/sfw/bin:/usr/ccs/bin:$PATH
# export PATH
# which gcc
# which make

# find ./ -name mod_rewrite.c //在apache的安裝目錄中尋找mod_rewrite.c檔案
# cd PATH/to/mod_rewrite.c //進入包含mod_rewrite.c檔案的目錄
# apxs -c mod_foo.c //apxs請指定絕對路徑,在你當前正在使用apache的bin目錄裡
# apxs -i -a -n mod_rewrite mod_rewrite.la

如果沒有什麼錯誤的話,應該在你的apache的modules目錄中編譯出一個mod_rewrite.so檔案。

編輯httpd.conf檔案,確認httpd.conf中已經包含mod_rewrite.so的加載語句,如下︰

LoadModule rewrite_module modules/mod_rewrite.so

這時,你的apache應該已經支援rewrite了。

二.基於PATH_INFO技術實現︰

修改phpBB代碼︰

打開overall_header.tpl檔案,在首行加如下代碼︰



打開config.php檔案,在?>前加入如下代碼︰

if ($REQUEST_METHOD == "GET") {
if (strlen(getenv('PATH_INFO')) > 1) {
$GET_array = array();
$PHP_SELF = str_replace(getenv('PATH_INFO'), '', $PHP_SELF);
$vars = explode('/', substr(getenv('PATH_INFO'), 1));
for ($i=0, $n=sizeof($vars); $i<$n; $i++) {
if (strpos($vars[$i], '[]')) {
$GET_array[substr($vars[$i], 0, -2)][] = $vars[$i+1];
} else {
$HTTP_GET_VARS[$vars[$i]] = $vars[$i+1];
}
$i++;
}
if (sizeof($GET_array) > 0) {
while (list($key, $value) = each($GET_array)) {
$HTTP_GET_VARS[$key] = $value;
}
}
}

}

if ($REQUEST_METHOD == "POST") {
if (strlen(getenv('PATH_INFO')) > 1) {
$POST_array = array();
$PHP_SELF = str_replace(getenv('PATH_INFO'), '', $PHP_SELF);
$vars = explode('/', substr(getenv('PATH_INFO'), 1));
for ($i=0, $n=sizeof($vars); $i<$n; $i++) {
if (strpos($vars[$i], '[]')) {
$POST_array[substr($vars[$i], 0, -2)][] = $vars[$i+1];
} else {
$HTTP_POST_VARS[$vars[$i]] = $vars[$i+1];
}
$i++;
}
if (sizeof($GET_array) > 0) {
while (list($key, $value) = each($POST_array)) {
$HTTP_POST_VARS[$key] = $value;
}
}
}

}

打開functions.php檔案,在?>前加入如下代碼︰

function replace_for_mod_rewrite($s) {

$s = str_replace("?", "/", $s);
$s = str_replace("&", "/", $s);
$s = str_replace("&", "/", $s);
$s = str_replace("=", "/", $s);
return $s;

}

打開sessions.php檔案,用下面代碼替換原來定義的append_sid()函數︰

function append_sid($url, $non_html_amp = false)
{
global $SID;


if ( !empty($SID) && !preg_match('#sid=#', $url) && !preg_match('#sid/#', $url) && !stristr( $_SERVER["HTTP_USER_AGENT"] ,'bot') && !stristr($_SERVER["HTTP_USER_AGENT"] ,'inktomi'))
{
$url .= ( ( strpos($url, '?') != false ) ? ( ( $non_html_amp ) ? '&' : '&' ) : '?' ) . $SID ;
}
$url=replace_for_mod_rewrite($url);
return $url;
}

這時,你的論壇URL將會映射成(http://www.domain/bbs/viewtopic.php/t/4)這種模式。

參考文獻︰

http://www.phpbb.com/phpBB/viewtopic.php?t=199008

http://www.phpbb.com/phpBB/viewtopic.php?t=137334



了解更多詳情,參與討論,請進入GBUNIX論壇︰

http://www.gbunix.com/bbs/forums.html


----------------------------------------------------------------------------

下面這個是在windows下的設定


PHP代碼:--------------------------------------------------------------------------------

http://wwww.aaaaaaaaa.com/bbb.php?id=888
的位址形式改為
http://wwww.aaaaaaaaa.com/888.htm
或者
http://wwww.aaaaaaaaa.com/yourname/888.htm
當然可以按照你的要求隨便變.
APACHE的 MOD_rewrite模塊.
大家可以看一個演示的一個 PHP學習論壇
http://www.phpx.com/happy/
這個論壇的版面和帖子,就是運用了這個技術,位址靜態化.但是是假的.
這個技術那裡好?
可以讓baidu, google等收入你的站點所有頁面.
收入位址就是你的假靜態位址.當然別人看不出你是假的.而且這個技術隱藏了你背後執行的程式.
你可以把
/soft/1234.html 重寫傳遞給 soft.php?id=1234
當然你改一下名 換成 softxfewafew.php?id=1234
表面還是 soft/1234.html但是你 APACHE內部執行了你重寫的檔案.
從根本上可以防止別人從程式本身入侵.

下面我寫怎么樣重寫.分為 WINDOWS和LIUNX2種
都是操作
APACHE安裝檔案夾內的 CONF檔案夾裡面的httpd.conf
打開以後,找到
#LoadModule rewrite_module "modules/mod_rewrite.so"
把#去掉.
然後找到虛擬主機配置
在虛擬主機中加入
RewriteEngine On
RewriteRule ^/soft/([0-9]+).html$ /soft.php?id=$1
//解釋
//WWW.玉米.COM/SOFT/1234.HTML
//重寫為
//WWW.玉米.COM/soft.php?id=1234
//這裡ID是可以變的 你給它 1 就是傳遞1
RewriteRule ^/([0-9]+).html$ /soft.php?id=$1
//解釋
//WWW.玉米.COM/1234.HTML
//重寫為
//WWW.玉米.COM/soft.php?id=1234
RewriteRule ^/([0-9]+)_([0-9]+).html$ /soft.php?id=$1&catid=$2
//解釋
//WWW.玉米.COM/1234_2222.HTML
//重寫為
//WWW.玉米.COM/soft.php?id=1234&catid=2222
當然隨便你怎么換!
這就是 WIN下的.
LIUNX下是一樣的 但是要加
開始
結束
重寫都加在虛擬主機設定中.
如果沒有虛擬主機,那加在最後!




---------------------------------------------------------------------------


Apache的ReWrite的應用

Apache的mod_rewrite是提供了強大URL操作的殺手級的模塊,可以實現幾乎所有你夢想的URL操作類型,其代價是你必須接受其複雜性,因為mod_rewrite的主要障礙就是初學人不容易理解和運用,即使是Apache專家有時也會發掘出mod_rewrite的新用途。

換句話說︰對mod_rewrite,或者是打退堂鼓永不再用,或者是喜歡它並一生受用。

ReWrite可以應用在以下方面或者解決以下問題︰
URL的規劃
規範的URL
說明:
在有些網站伺服器上,一個資源會擁有多個URL,在實際應用和發布中應該被使用的是規範的URL,其他的則是簡寫或者是內部使用的。無論用戶在請求中使用什麼形式的URL,他最終看見的都應該是規範的URL。

方案:
對所有的不規範的URL執行一個外部的HTTP重定向,以改變它在瀏覽器位址欄中的顯示及其後繼的請求。下例中的規則集用規範的/u/user替換/~user,並修正了/u/user所遺漏的後綴的斜杠。



代碼:
RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]


規範的主機名
說明:
...
方案:
代碼:
RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{SERVER_PORT} !^80$
RewriteRule ^/(.*) http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST} !^$
RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]


被移動過的DocumentRoot
說明:
通常,網站伺服器的DocumentRoot直接對應於URL"/",但是,它常常不是處於最高一級,而可能只是眾多數據池中的一個實體。比如,在Intranet站點中,有/e/www/(WWW的主頁)、/e/sww/ (Intranet的主頁)等等,而DocumentRoot指向了/e/www/,則必須保證此數據池中的所有內嵌的圖片和其他元素對後繼請求有效。

方案:
只須重定向URL /到/e/www/即可。這個方案看起來很簡單,但只是有了mod_rewrite模塊的支援,它才簡單,因為道統的URL Aliases機製(由mod_alias及其相關模塊提供)只是作了一個前綴匹配,DocumentRoot是一個對所有URL的前綴,因而無法實現這樣的重定向。而用mod_rewrite的確很簡單:

代碼:
RewriteEngine on
RewriteRule ^/$ /e/www/ [R]


後綴斜杠的問題
說明:
每個網管對引用目錄後綴斜杠的問題都有一本苦經,如果遺漏了,伺服器會產生一個錯誤,因為如果請求是/~quux/foo而不是/~quux/foo/,伺服器會去找一個叫foo的檔案,而它是一個目錄,所以就報錯了。事實上,大多數情況下,它自己會試圖修正這個錯誤,但是有時候需要你手工糾正,比如,在重寫了許多CGI腳本中的複雜的URL以後。

方案:
解決這個微妙問題的方案是讓伺服器自動添加後綴的斜杠。對此,必須使用一個外部的重定向,使瀏覽器正確地處理後繼的對諸如圖片的請求。如果僅僅作一個內部的重寫,可能只對目錄頁面有效,而對內嵌有使用相對URL的圖片的頁面則無效,因為瀏覽器有請求內嵌目標的可能。比如,如果不用外部重定向,/~quux/foo/index.html頁面中對image.gif的請求,其結果將是/~quux/image.gif﹗。

所以,應該這樣寫︰

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo$ foo/ [R]

又懶又瘋狂的做法是把這些寫入其宿主目錄中的頂級.htaccess中,但是須注意,如此會帶來一些處理上的開銷。

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]


集群網站的同類URL規劃
說明:
我們希望在一個Intranet集群網站中,對所有WWW伺服器建立一個同類的一致性的URL規劃,也就是,所有的URL(對單個伺服器來說,是本地的倚賴於此伺服器的﹗)是獨立於伺服器的﹗我們需要的是一個具有獨立於伺服器的一致性規劃的WWW名稱空間,即,URL不需要包含正確的物理的目標伺服器,而由集群本身來自動定位物理的目標主機。

方案:
首先,目標伺服器的訊息來自(產生)於包含有用戶、組以及實體的外部地圖,其格式形如︰

代碼:
user1 server_of_user1
user2 server_of_user2
: :


這些訊息被存入map.xxx-to-host檔案。其次,如果URL在一個伺服器上無效,需要引導所有的伺服器重定向URL

代碼:
/u/user/anypath
/g/group/anypath
/e/entity/anypath



代碼:
http://physical-host/u/user/anypath
http://physical-host/g/group/anypath
http://physical-host/e/entity/anypath


以下規則集依靠地圖檔案來完成這個操作(假定,如果一個用戶在地圖中沒有對應的項,則使用server0為預設伺服器)︰

代碼:
RewriteEngine on

RewriteMap user-to-host txt:/path/to/map.user-to-host
RewriteMap group-to-host txt:/path/to/map.group-to-host
RewriteMap entity-to-host txt:/path/to/map.entity-to-host

RewriteRule ^/u/([^/]+)/?(.*) http://${user-to-host:$1|server0}/u/$1/$2
RewriteRule ^/g/([^/]+)/?(.*) http://${group-to-host:$1|server0}/g/$1/$2
RewriteRule ^/e/([^/]+)/?(.*) http://${entity-to-host:$1|server0}/e/$1/$2

RewriteRule ^/([uge])/([^/]+)/?$ /$1/$2/.www/
RewriteRule ^/([uge])/([^/]+)/([^.]+.+) /$1/$2/.www/$3\


移動宿主目錄到不同的網站伺服器
說明:
通常,許多網管在建立一個新的網站伺服器時,都會有這樣的要求︰重定向一個網站伺服器上的所有宿主目錄到另一個網站伺服器。

方案:
很簡單,用mod_rewrite。在老的網站伺服器上重定向所有的URL /~user/anypath到http://newserver/~user/anypath。

代碼:
RewriteEngine on
RewriteRule ^/~(.+) http://newserver/~$1 [R,L]


架構化的宿主目錄
說明:
一些擁有幾千個用戶的網站通常都使用架構化的宿主目錄規劃,即,每個宿主目錄位於一個帶有特定前綴比如其用戶名的第一個字符的次目錄下。那麼,/~foo/anypath代表/home/f/foo/.www/anypath,而/~bar/anypath代表/home/b/bar/.www/anypath。

方案:
可以使用下列規則集來擴展~以達到上述目的。

代碼:
RewriteEngine on
RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3


檔案系統的重組
說明:
這是一個不加雕琢的例子︰一個大量使用針對目錄的規則集以實現平滑觀感,而從來不用調整數據架構的殺手級的應用。背景︰net.sw從1992年開始,存放了我收集的免費的有效的Unix套裝軟件。它是我的愛好也是我的工作,因為在學習計算機科學的同時,業餘時間還做了多年的系統和網路的管理員。每周我都需要整理軟體,因而建立了一個層次很深的目錄架構來存放各種套裝軟件︰

代碼:
drwxrwxr-x 2 netsw users 512 Aug 3 18:39 Audio/
drwxrwxr-x 2 netsw users 512 Jul 9 14:37 Benchmark/
drwxrwxr-x 12 netsw users 512 Jul 9 00:34 Crypto/
drwxrwxr-x 5 netsw users 512 Jul 9 00:41 Database/
drwxrwxr-x 4 netsw users 512 Jul 30 19:25 Dicts/
drwxrwxr-x 10 netsw users 512 Jul 9 01:54 Graphic/
drwxrwxr-x 5 netsw users 512 Jul 9 01:58 Hackers/
drwxrwxr-x 8 netsw users 512 Jul 9 03:19 InfoSys/
drwxrwxr-x 3 netsw users 512 Jul 9 03:21 Math/
drwxrwxr-x 3 netsw users 512 Jul 9 03:24 Misc/
drwxrwxr-x 9 netsw users 512 Aug 1 16:33 Network/
drwxrwxr-x 2 netsw users 512 Jul 9 05:53 Office/
drwxrwxr-x 7 netsw users 512 Jul 9 09:24 SoftEng/
drwxrwxr-x 7 netsw users 512 Jul 9 12:17 System/
drwxrwxr-x 12 netsw users 512 Aug 3 20:15 Typesetting/
drwxrwxr-x 10 netsw users 512 Jul 9 14:08 X11/

1996年7月,我決定透過一個漂亮的Web界面公開我的收藏。"漂亮"是指提供一個界面以直接瀏覽整個目錄架構,同時不對這個架構做任何改變 - 甚至也不在架構頂部放置CGI腳本。為什麼呢?因為這個架構還要能夠被FTP訪問,而且我不希望其中有任何Web或者CGI的成分。

方案:
這個方案分為兩個部分︰第一個部分,是用於在空閒時間建立所有目錄頁面的CGI腳本集。我把它們放在/e/netsw/.www/,如下︰

代碼:
-rw-r--r-- 1 netsw users 1318 Aug 1 18:10 .wwwacl
drwxr-xr-x 18 netsw users 512 Aug 5 15:51 DATA/
-rw-rw-rw- 1 netsw users 372982 Aug 5 16:35 LOGFILE
-rw-r--r-- 1 netsw users 659 Aug 4 09:27 TODO
-rw-r--r-- 1 netsw users 5697 Aug 1 18:01 netsw-about.html
-rwxr-xr-x 1 netsw users 579 Aug 2 10:33 netsw-access.pl
-rwxr-xr-x 1 netsw users 1532 Aug 1 17:35 netsw-changes.cgi
-rwxr-xr-x 1 netsw users 2866 Aug 5 14:49 netsw-home.cgi
drwxr-xr-x 2 netsw users 512 Jul 8 23:47 netsw-img/
-rwxr-xr-x 1 netsw users 24050 Aug 5 15:49 netsw-lsdir.cgi
-rwxr-xr-x 1 netsw users 1589 Aug 3 18:43 netsw-search.cgi
-rwxr-xr-x 1 netsw users 1885 Aug 1 17:41 netsw-tree.cgi
-rw-r--r-- 1 netsw users 234 Jul 30 16:35 netsw-unlimit.lst


其中的DATA/次目錄包含了上述目錄架構,即實在的net.sw,由rdist在需要的時候自動更新。第二個部分的遺留問題是︰如何連接這兩個架構為一個平滑觀感的URL樹?我希望在營運適當的CGI腳本而使用各種URL的時候,使用戶感覺不到DATA/目錄的存在。方案如下︰首先,我把下列配置放在伺服器上DocumentRoot中的針對目錄的配置檔案裡,以重寫公佈的URL /net.sw/ 為內部路徑 /e/netsw︰

代碼:
RewriteRule ^net.sw$ net.sw/ [R]
RewriteRule ^net.sw/(.*)$ e/netsw/$1


第一條規則是針對遺漏後綴斜杠的請求的﹗第二條規則才是真正實現功能的。接著,就是放在針對目錄的配置檔案/e/netsw/.www/.wwwacl中的殺手級的配置了︰

代碼:
Options ExecCGI FollowSymLinks Includes MultiViews

RewriteEngine on

# we are reached via /net.sw/ prefix
RewriteBase /net.sw/

# first we rewrite the root dir to
# the handling cgi script
RewriteRule ^$ netsw-home.cgi [L]
RewriteRule ^index\.html$ netsw-home.cgi [L]

# strip out the subdirs when
# the browser requests us from perdir pages
RewriteRule ^.+/(netsw-[^/]+/.+)$ $1 [L]

# and now break the rewriting for local files
RewriteRule ^netsw-home\.cgi.* - [L]
RewriteRule ^netsw-changes\.cgi.* - [L]
RewriteRule ^netsw-search\.cgi.* - [L]
RewriteRule ^netsw-tree\.cgi$ - [L]
RewriteRule ^netsw-about\.html$ - [L]
RewriteRule ^netsw-img/.*$ - [L]

# anything else is a subdir which gets handled
# by another cgi script
RewriteRule !^netsw-lsdir\.cgi.* - [C]
RewriteRule (.*) netsw-lsdir.cgi/$1


閱讀提示:

注意前半部分中的標誌L(最後),和無對應項('-')
注意後半部分中的符號!(非),和標誌C (鏈)
注意最後一條規則的全匹配模式
代碼:
NCSA imagemap和Apache mod_imap
說明:
許多人都希望在從NCSA網站伺服器向較現代的Apache網站伺服器轉移中實現平滑過渡,即希望老的NCSA imagemap程式能在Apache的較現代的mod_imap支援下正常運作。但問題在於,到處都是透過/cgi-bin/imagemap/path/to/page.map引用imagemap程式的連接,而在Apache下,應該寫成/path/to/page.map。

方案:
使用全局規則在空閒時間去除所有這些請求的前綴︰

代碼:
RewriteEngine on
RewriteRule ^/cgi-bin/imagemap(.*) $1 [PT]


在多個目錄中搜索頁面
說明:
有時會有必要使網站伺服器在多個目錄中搜索頁面,對此,MultiViews或者其他技術無能為力。

方案:
編製一個明確的規則集以搜索目錄中的檔案。

代碼:
RewriteEngine on

# first try to find it in custom/...
# ...and if found stop and be happy:
RewriteCond /your/docroot/dir1/%{REQUEST_FILENAME} -f
RewriteRule ^(.+) /your/docroot/dir1/$1 [L]

# second try to find it in pub/...
# ...and if found stop and be happy:
RewriteCond /your/docroot/dir2/%{REQUEST_FILENAME} -f
RewriteRule ^(.+) /your/docroot/dir2/$1 [L]

# else go on for other Alias or ScriptAlias directives,
# etc.
RewriteRule ^(.+) - [PT]


按照URL的片段設定環境變量
說明:
如果希望保持請求之間的狀態訊息,但又不希望使用CGI來包裝所有頁面,而只透過分離URL中的有用訊息來編碼。

方案:
可以用一個規則集來分離出狀態訊息,並設定環境變量以備此後用於XSSI或CGI。如此,一個/foo/S=java/bar/的URL會被解析為/foo/bar/,而環境變量STATUS則被設定為"java"。

代碼:
RewriteEngine on
RewriteRule ^(.*)/S=([^/]+)/(.*) $1/$3 [E=STATUS:$2]


虛擬用戶主機
說明:
如果需要為用戶username支援一個www.username.host.domain.com的主頁,但不是用在此機器上建虛擬主機的方法,而是用僅在此機器上增加一個DNS記錄的方法實現。

方案:
對HTTP/1.0的請求,這是無法實現的;但是對HTTP/1.1的在HTTP頭中包含有主機名的請求,可以用以下規則集來內部地重寫http://www.username.host.com/anypath為/home/username/anypath︰

代碼:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.[^.]+\.host\.com$
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
RewriteRule ^www\.([^.]+)\.host\.com(.*) /home/$1$2


為外來訪問者重定向宿主目錄
說明:
對不是來自本地域ourdomain.com的外來訪問者的請求,重定向其宿主目錄URL到另一個網站伺服器www.somewhere.com,有時這種做法也會用在虛擬主機的上下文中。

方案:
只須一個重寫條件:

代碼:
RewriteEngine on
RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]


重定向失敗的URL到其他網站伺服器
說明:
如何重寫URL以重定向對網站伺服器A的失敗請求到伺服器B,是一個常見的問題。一般,可以用Perl寫的CGI腳本透過ErrorDocument來解決,此外,還有mod_rewrite方案。但是須注意,這種方法的執行效率不如用ErrorDocument的CGI腳本!

方案:
第一種方案,有最好的性能而靈活性欠佳,出錯機率小所以安全:

代碼:
RewriteEngine on
RewriteCond /your/docroot/%{REQUEST_FILENAME} !-f
RewriteRule ^(.+) http://webserverB.dom/$1


但是其問題在於,它只對位於DocumentRoot中的頁面有效。雖然可以增加更多的條件(比如同時還處理宿主目錄,等等),但是還有一個更好的方法︰

代碼:
RewriteEngine on
RewriteCond %{REQUEST_URI} !-U
RewriteRule ^(.+) http://webserverB.dom/$1


這種方法使用了mod_rewrite提供的"向前參照(look-ahead)"的功能,是一種對所有URL類型都有效而且安全的方法。但是,對網站伺服器的性能會有影響,所以如果網站伺服器有一個強大的CPU,那就用這個方法。而在慢速機器上,可以用第一種方法,或者用性能更好的ErrorDocument CGI腳本。

擴展的重定向
說明:
有時候,我們會需要更多的對重定向URL的(有關字符轉義機製方面的)控制。通常,Apache內核中的URL轉義函數uri_escape()同時還會對anchor轉義,即,類似"url#anchor"的URL,因此,你不能用mod_rewrite對此類URL直接重定向。那麼如何實現呢?

方案:
必須用NPH-CGI腳本使它自己重定向,因為對NPH(non-parseable headers [無須解析的HTTP頭])不會發生轉義操作。首先,在針對伺服器的配置中(應該位於所有重寫規則的最後),引入一種新的URL類型xredirect:︰

代碼:
RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
[T=application/x-httpd-cgi,L]


以強製所有帶xredirect:前綴的URL被傳送到如下的nph-xredirect.cgi程式︰

代碼:
#!/path/to/perl
##
## nph-xredirect.cgi -- NPH/CGI script for extended redirects
## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##

$| = 1;
$url = $ENV{'PATH_INFO'};

print "HTTP/1.0 302 Moved Temporarily\n";
print "Server: $ENV{'SERVER_SOFTWARE'}\n";
print "Location: $url\n";
print "Content-type: text/html\n";
print "\n";
print "\n";
print "\n";
print "\n";
print "\n";
print "\n";
print "
Moved Temporarily (EXTENDED)
\n";
print "The document has moved here.
\n";
print "\n";
print "\n";

##EOF##



這是一種可以重定向所有URL類型的方法,包括不被mod_rewrite直接支援的類型。所以,還可以這樣重定向news:newsgroup︰

代碼:
RewriteRule ^anyurl xredirect:news:newsgroup


注意︰無須對上述規則加[R]或[R,L],因為xredirect:會在稍後被其特殊的傳送規則擴展。
文檔訪問的多路複用
說明:
你知道http://www.perl.com/CPAN的CPAN(Comprehensive Perl Archive Network)嗎?它實現了一個重定向以提供,全世界的CPAN鏡像中離訪問者最近的一個FTP站點,也可以稱之為FTP訪問多路複用服務。CPAN是透過CGI腳本實現的,那麼用mod_rewrite如何實現呢?

方案:
首先,我們注意到mod_rewrite從3.0.0版本開始,還可以重寫"ftp:"類型。其次,對客戶端頂級域名的路徑最近的求取可以用RewriteMap實現。利用鏈式規則集,並用頂級域名作為查找多路複用地圖的鍵,可以這樣做︰

代碼:
RewriteEngine on
RewriteMap multiplex txt:/path/to/map.cxan
RewriteRule ^/CxAN/(.*) %{REMOTE_HOST}::$1 [C]
RewriteRule ^.+\.([a-zA-Z]+)::(.*)$ ${multiplex:$1|ftp.default.dom}$2 [R,L]

##
## map.cxan -- Multiplexing Map for CxAN
##

de ftp://ftp.cxan.de/CxAN/
uk ftp://ftp.cxan.uk/CxAN/
com ftp://ftp.cxan.com/CxAN/
:
##EOF##

倚賴於時間的重寫
說明:
在頁面內容依時間不同而變化的場合,比如重定向特定頁面,許多網管仍然採用CGI腳本的方法,如何用mod_rewrite來實現呢?

方案:
有許多類似TIME_xxx的變量可以用在重寫條件中,利用STRING和=STRING的類型比較,並加以連接,就可以實現倚賴於時間的重寫︰

代碼:
RewriteEngine on
RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
RewriteRule ^foo\.html$ foo.day.html
RewriteRule ^foo\.html$ foo.night.html


此例使URL foo.html在07:00-19:00時指向foo.day.html,而在其餘時間,則指向foo.night.html,對主頁是一個不錯的功能...

對YYYY過渡為XXXX的向前兼容
說明:
在轉變了大批.html檔案為.phtml,使文檔.YYYY過渡成為文檔.XXXX後,如何保持URL的向前兼容(仍然虛擬地存在)?

方案:
只須按基準檔案名重寫,並測試帶有新的擴展名的檔案是否存在,如果存在,則用新的,否則,仍然用原來的。

代碼:
# backward compatibility ruleset for
# rewriting document.html to document.phtml
# when and only when document.phtml exists
# but no longer document.html
RewriteEngine on
RewriteBase /~quux/
# parse out basename, but remember the fact
RewriteRule ^(.*)\.html$ $1 [C,E=WasHTML:yes]
# rewrite to document.phtml if exists
RewriteCond %{REQUEST_FILENAME}.phtml -f
RewriteRule ^(.*)$ $1.phtml [S=1]
# else reverse the previous basename cutout
RewriteCond %{ENV:WasHTML} ^yes$
RewriteRule ^(.*)$ $1.html



內容的處理
新舊URL(內部的)
說明:
假定已經把檔案bar.html改名為foo.html,需要對老的URL向前兼容,即讓用戶仍然可以使用老的URL,而感覺不到檔案被改名了。

方案:
透過以下規則內部地重寫老的URL為新的︰

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo\.html$ bar.html


新舊URL(外部的)
說明:
仍然假定已經把檔案bar.html改名為foo.html,需要對老的URL向前兼容,但是要讓用戶得到檔案被改名的暗示,即,其瀏覽器的位址欄中顯示的是新的URL。

方案:
作一個HTTP的強製重定向以改變瀏覽器和用戶界面上的顯示︰

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo\.html$ bar.html [R]


倚賴於瀏覽器的內容
說明:
至少對重要的頂級頁面,有時候有必要提供倚賴於瀏覽器的最佳的內容,即對最新的Netscape提供最大化的版本,對Lynx提供最小化的版本,而對其他的瀏覽器則提供一個功能一般的版本。

方案:
對此,內容協商無能為力,因為瀏覽器不提供其那種形式的類型,所以只能在HTTP頭"User-Agent"上想辦法。以下規則集可以完成這個操作︰如果HTTP頭"User-Agent"以"Mozilla/3"開頭,則頁面foo.html被重寫為foo.NS.html,而後重寫操作終止;如果是"Lynx"或者版本號為1和2的"Mozilla",則重寫為foo.20.html;而其他所有的瀏覽器收到的頁面則是foo.32.html︰

代碼:
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
RewriteRule ^foo\.html$ foo.NS.html [L]

RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
RewriteRule ^foo\.html$ foo.20.html [L]

RewriteRule ^foo\.html$ foo.32.html [L]


動態鏡像
說明:
假定,需要在我們的名稱空間裡加入其他遠程主機的頁面。對FTP伺服器,可以用mirror程式以在本地機器上維持一個對遠程數據的最新的拷貝;對網站伺服器,可以用類似的用於HTTP的webcopy程式。但這兩種技術都有一個主要的缺點︰此本地拷貝必須透過這個程式的執行來更新。所以,比較好的方法是,不採用靜態鏡像,而採用動態鏡像,即,在有數據請求時自動更新(遠程主機上更新的數據)。

方案:
為此,使用Proxy Throughput功能(flag [P]),以映射遠程頁面甚至整個遠程網路區域到我們的名稱空間︰

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^hotsheet/(.*)$ http://www.tstimpreso.com/hotsheet/$1 [P]

RewriteEngine on
RewriteBase /~quux/
RewriteRule ^usa-news\.html$ http://www.quux-corp.com/news/index.html [P]


反向動態鏡像
說明:
...
方案:
代碼:
RewriteEngine on
RewriteCond /mirror/of/remotesite/$1 -U
RewriteRule ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1


透過Intranet取得丟失的數據
說明:
這是一種在受防火牆保護的(內部的)Intranet(www2.quux-corp.dom)上儲存和維護實際數據,而虛擬地營運企業級(外部的)Internet網站伺服器(www.quux-corp.dom)的巧妙的方法。這種方法是外部伺服器在空閒時間從內部伺服器取得被請求的數據。

方案:
首先,必須確保防火牆對內部伺服器的保護,並只允許此外部伺服器取得數據。對包過濾(packet-filtering)防火牆,可以如下製定防火牆規則︰

代碼:
ALLOW Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port 80
DENY Host * Port * --> Host www2.quux-corp.dom Port 80


按你的實際配置,只要對上例稍作調整即可。接著,建立透過代理後台獲取丟失數據的mod_rewrite規則︰

代碼:
RewriteRule ^/~([^/]+)/?(.*) /home/$1/.www/$2
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/home/([^/]+)/.www/?(.*) http://www2.quux-corp.dom/~$1/pub/$2 [P]


負載的均衡
說明:
如何均衡www.foo.com的負載到www[0-5].foo.com(一共是6個伺服器)?

方案:
這個問題有許多可能的解決方案,在此,我們討論通稱為"基於DNS(DNS-based)的"方案,和特殊的使用mod_rewrite的方案:

DNS循環(DNS Round-Robin)
最簡單的方法是用BIND的DNS循環特性,只要按慣例設定www[0-9].foo.com的DNS的A(位址)記錄,如︰

代碼:
www0 IN A 1.2.3.1
www1 IN A 1.2.3.2
www2 IN A 1.2.3.3
www3 IN A 1.2.3.4
www4 IN A 1.2.3.5
www5 IN A 1.2.3.6


然後,增加以下各項:

代碼:
www IN CNAME www0.foo.com.
IN CNAME www1.foo.com.
IN CNAME www2.foo.com.
IN CNAME www3.foo.com.
IN CNAME www4.foo.com.
IN CNAME www5.foo.com.
IN CNAME www6.foo.com.


注意,上述看起來似乎是錯誤的,但事實上,它的確是BIND中的一個預期的特性,而且也可以這樣用。無論如何,現下www.foo.com已經被解析,BIND可以給出www0-www6 - 雖然每次在次序上會有輕微的置換/循環,客戶端的請求可以被分散到各個伺服器。可是,這並不是一個優秀的負載均衡方案,因為,DNS解析訊息可以被網路中其他名稱伺服器緩沖,而一旦www.foo.com被解析為wwwN.foo.com,則其後繼請求都將被送往www.foo.com。但是最終結果是正確的,因為請求的總量的確被分散到各個伺服器了

DNS 負載均衡
一種成熟的基於DNS的負載均衡方法是使用http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html的lbnamed程式,它是一個Perl 5程式,帶有若干輔助工具,實現了真正的基於DNS的負載均衡。

代理吞吐循環(Proxy Throughput Round-Robin)
這是一個使用mod_rewrite及其代理吞吐特性的方法。首先,在DNS記錄中,將www0.foo.com固定為www.foo.com,如下︰

代碼:
www IN CNAME www0.foo.com.


其次,將www0.foo.com轉換為一個專職代理伺服器,即,由這個機器把所有到來的URL透過內部代理分散到另外5個伺服器(www1-www5)。為此,必須建立一個規則集,對所有URL調用一個負載均衡腳本lb.pl。

代碼:
RewriteEngine on
RewriteMap lb prg:/path/to/lb.pl
RewriteRule ^/(.+)$ ${lb:$1} [P,L]


以下是lb.pl:

代碼:
#!/path/to/perl
##
## lb.pl -- load balancing script
##

$| = 1;

$name = "www"; # the hostname base
$first = 1; # the first server (not 0 here, because 0 is myself)
$last = 5; # the last server in the round-robin
$domain = "foo.dom"; # the domainname

$cnt = 0;
while () {
$cnt = (($cnt+1) % ($last+1-$first));
$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
print "http://$server/$_";
}

##EOF##

最後的說明︰這樣有用嗎?www0.foo.com似乎也會超載呀?答案是︰沒錯,它的確會超載,但是它超載的僅僅是簡單的代理吞吐請求﹗所有諸如SSI、CGI、ePerl等等的處理完全是由其他機器完成的,這個才是要點。
硬體/TCP循環
還有一個硬體解決方案。Cisco有一個叫LocalDirector的東西,實現了TCP/IP層的負載均衡,事實上,它是一個位於網站集群前端的電路級通訊閘。如果你有足夠資金而且的確需要高性能的解決方案,那麼可以用這個。

反向代理
說明:
...
方案:
代碼:
##
## 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

Options -FollowSymLinks -SymLinksIfOwnerMatch
AllowOverride None


# the status page for monitoring the reverse proxy

SetHandler server-status


# 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/

##
## 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


新的MIME類型,新的服務
說明:
網上有許多很技巧的CGI程式,但是用法晦澀,許多網管棄之不用。即使是Apache的MEME類型的動作處理器,也僅僅在CGI程式不需要在其輸入中包含特殊URL(PATH_INFO和QUERY_STRINGS)時才很好用。首先,配置一種新的後綴為.scgi(for secure CGI)檔案類型,其處理器是很常見的cgiwrap程式。問題是︰如果使用同類URL規劃(見上述),而用戶宿主目錄中的一個檔案的URL是/u/user/foo/bar.scgi,可是cgiwrap要求的URL的格式是/~user/foo/bar.scgi/,以下規則解決了這個問題︰

代碼:
RewriteRule ^/[uge]/([^/]+)/\.www/(.+)\.scgi(.*) ...
... /internal/cgi/user/cgiwrap/~$1/$2.scgi$3 [NS,T=application/x-http-cgi]


另外,假設需要使用其他程式︰wwwlog(顯示access.log中的一個URL子樹)和wwwidx(對一個URL子樹營運Glimpse),則必須對這些程式提供URL區域作為其操作對象。比如,對/u/user/foo/執行swwidx程式的超鏈是這樣的︰

代碼:
/internal/cgi/user/swwidx?i=/u/user/foo/


其缺點是,必須同時硬編碼超鏈中的區域和CGI的路徑,如果重組了這個區域,就需要花費大量時間來修改各個超鏈。

方案:
方案是用一個特殊的新的URL格式,自動拼裝CGI參數︰

代碼:
RewriteRule ^/([uge])/([^/]+)(/?.*)/\* /internal/cgi/user/wwwidx?i=/$1/$2$3/
RewriteRule ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3


現下,這個搜索到/u/user/foo/的超鏈簡化成了︰

代碼:
HREF="*"


它會被內部地自動轉換為

代碼:
/internal/cgi/user/wwwidx?i=/u/user/foo/


如此,可以為使用:log的超鏈,拼裝出調用CGI程式的參數。

從靜態到動態
說明:
如何無縫轉換靜態頁面foo.html為動態的foo.cgi,而不為瀏覽器/用戶所察覺。

方案:
只須重寫此URL為CGI-script,以強製為可以作為CGI-script營運的正確的MIME類型。如此,對/~quux/foo.html的請求其實會執行/~quux/foo.cgi。

代碼:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]


空閒時間內的內容協商
說明:
這是一個很難解的功能︰動態生成的靜態頁面,即,它應該作為靜態頁面發送(從檔案系統中讀出,然後直接發出去),但是如果它丟失了,則由伺服器動態生成。如此,可以靜態地提供CGI生成的頁面,除非有人(或者是一個cronjob)刪除了這些靜態頁面,而且其內容可以得到更新。

方案:
以下規則集實現這個功能︰
代碼:
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^page\.html$ page.cgi [T=application/x-httpd-cgi,L]
這樣,如果page.html不存在或者檔案大小為null,則對page.html的請求會導致page.cgi的營運。其中奧妙在於,page.cgi是一個將輸出寫入page.html的(同時也寫入STDOUT)的常規的CGI腳本,執行完畢,伺服器則將page.html的內容發出。如果網管需要強製更新其內容,只須刪除page.html即可(通常由一個cronjob完成)。

自動更新的文檔
說明:
建立一個複雜的頁面,能夠在用編輯器寫了一個更新的版本時自動在瀏覽器上得到刷新,這不是很好嗎?這可能嗎?

方案:
這是可行的! 這需要綜合利用MIME多成分、網站伺服器的NPH和mod_rewrite的URL操控特性。首先,建立一個新的URL特性︰對在檔案系統中更新時需要刷新的所有URL加上:refresh。

代碼:
RewriteRule ^(/[uge]/[^/]+/?.*):refresh /internal/cgi/apache/nph-refresh?f=$1


然後,修改URL

代碼:
/u/foo/bar/page.html:refresh


以內部地操控此URL

代碼:
/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html


接著就是NPH-CGI腳本部分了。雖然,人們常說"left as an exercise to the reader",我還是給出答案了。

代碼:
#!/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 "&b&ERROR&/b&: 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 "&b&ERROR&/b&: 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, "&$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 & $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);
}
}

&print_http_headers_multipart_end;

exit(0);

##EOF##
湮 剞
:
Apache腔髡夔竭?ㄛ 衄 跺剞 腔? 堍 腕竭疑ㄛ ? ISPㄛ 猁 鼎 啃跺剞 ㄛ 憩祥 跺 槽腔恁

源偶:
森ㄛ 猁 (Proxy Throughput)髡夔(flag [P])茬 最 跺 最 ? 善 撩腔靡 ㄩ

:
##
## vhost.map
##
www.vhost1.dom:80 /path/to/docroot/vhost1
www.vhost2.dom:80 /path/to/docroot/vhost2
:
www.vhostN.dom:80 /path/to/docroot/vhostN

:
##
## httpd.conf
##
:
# use the canonical hostname on redirects, etc.
UseCanonicalName on

:
# add the virtual host in front of the CLF-format
CustomLog /path/to/access_log "%{VHOST}e %h %l %u %t \"%r\" %>s %b"
:

# enable the rewriting engine in the main server
RewriteEngine on

# define two maps: one for fixing the URL and one which defines
# the available virtual hosts with their corresponding
# DocumentRoot.
RewriteMap lowercase int:tolower
RewriteMap vhost txt:/path/to/vhost.map

# Now do the actual virtual host mapping
# via a huge and complicated single rule:
#
# 1. make sure we don't map for common locations
RewriteCond %{REQUEST_URL} !^/commonurl1/.*
RewriteCond %{REQUEST_URL} !^/commonurl2/.*
:
RewriteCond %{REQUEST_URL} !^/commonurlN/.*
#
# 2. make sure we have a Host header, because
# currently our approach only supports
# virtual hosting through this header
RewriteCond %{HTTP_HOST} !^$
#
# 3. lowercase the hostname
RewriteCond ${lowercase:%{HTTP_HOST}|NONE} ^(.+)$
#
# 4. lookup this hostname in vhost.map and
# remember it only when it is a path
# (and not "NONE" from above)
RewriteCond ${vhost:%1} ^(/.*)$
#
# 5. finally we can map the URL to its docroot location
# and remember the virtual host for logging puposes
RewriteRule ^/(.*)$ %1/$1 [E=VHOST:${lowercase:%{HTTP_HOST}}]
:


勤 腔
郯砦Robots
:
?睡郯砦 跺 ?曩靡腔robot?腕 隅 ? 腔 跺/robots.txt 璃褫 漪? "Robot Exclusion Protocol(robot 祜)"腔 ㄛ 祥逋 郯砦森 robot

源偶:
褫 跺寞 摩 勤 ? /~quux/foo/arc/(勤 跺竭旮腔醴 ? 蹈桶褫夔 督 ?莉汜竭湮腔蛹 )腔 斛 ? 躺郯砦 隅腔robotㄛ憩 ㄛ躺躺郯砦robot 祥劂腔ㄛ 骯 珩郯砦 森ㄛ憩 猁勤HTTP 腔User-Agent ?

:
RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
RewriteRule ^/~quux/foo/arc/.+ - [F]
郯砦 ?腔 ?
:
ㄛhttp://www.quux-corp.de/~quux/衄 ? ?腔 ㄛ ?竭疑ㄛ 憩衄? 蟀善坻 撩腔 蠶衾 ? 腔督 ?腔霜 ㄛ 森ㄛ 祥堋砩 笱岈?楷汜

源偶:
?ㄛ 祥夔100% ?祥掩 ?梗?腔 ㄛ 褫 勤楷堤HTTP Referer 腔 ?

:
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
RewriteRule .*\.gif$ - [F]

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
RewriteRule ^inlined-in-foo\.gif$ - [F]


勤 腔
:
?睡 窒蹈桶 腔 勤 督 ?腔

源偶:
:
For Apache >= 1.3b6:

RewriteEngine on
RewriteMap hosts-deny txt:/path/to/hosts.deny
RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^/.* - [F]

For Apache <= 1.3b6:

RewriteEngine on
RewriteMap hosts-deny txt:/path/to/hosts.deny
RewriteRule ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
RewriteRule !^NOT-FOUND/.* - [F]
RewriteRule ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
RewriteRule !^NOT-FOUND/.* - [F]
RewriteRule ^NOT-FOUND/(.*)$ /$1

:
##
## hosts.deny
##
## ATTENTION! This is a map, not a list, even when we treat it as such.
## mod_rewrite parses it for key/value pairs, so at least a
## dummy value "-" must be present for each entry.
##

193.102.180.41 -
bsdti1.sdm.de -
192.76.162.40 -

勤 腔
:
?睡 跺 氪懂 隅 腔 Apache

源偶:
忑珂ㄛ猁? Apache 桴督 ? 晤 離 璃 mod_rewrite mod_proxy腔 (!)ㄛ 坳 mod_proxy ?掩覃 ? ㄛ? 跺 ...

:
RewriteCond %{REMOTE_HOST} ^badhost\.mydomain\.com$
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]

...? user@host-dependent:

:
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} ^badguy@badhost\.mydomain\.com$
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]


腔?
:
衄 ㄛ 猁 笱 都 腔? ㄛ ㄛ勤 ?硌隅腔 ㄛ ? ㄛ 衄( mod_access腔 ? 源 褫夔 堤 腔)?睡

源偶:
褫 跺 沭璃蹈桶懂 衄腔 ㄩ

:
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^[email protected]\.com$
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^[email protected]\.com$
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^[email protected]\.com$
RewriteRule ^/~quux/only-for-friends/ - [F]


衾 蝠氪(Referer)腔 ?
:
?睡 離 跺 衾HTTP "Referer"腔 ? 善?砩 腔 蝠 ?

源偶:
跺竭撮?腔寞 摩...

:
RewriteMap deflector txt:/path/to/deflector.map

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
RewriteRule ^.* %{HTTP_REFERER} [R,L]

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]


... 甜 磁勤茼腔 :

:
##
## deflector.map
##

http://www.badguys.com/bad/index.html -
http://www.badguys.com/bad/index2.html -
http://www.badguys.com/bad/index3.html http://somewhere.com/

坳褫 雄蔚??( 硌隅 "-" 腔 ) 隙? 蝠 ㄛ 氪( URL衄 跺 ) 善 跺 隅腔URL


?坻
窒 ?
:
跺都獗腔 : ?睡 樵侔 mod_rewrite 樵腔FOO/BAR/QUUX/ 腔

源偶:
褫 跺 RewriteMap髡夔眈骯腔 窒RewriteMap最 ㄛ 筒坳 Apache?雄 掩硒 ㄛ 植STDIN 掩??腔URLㄛ甜蔚揭 ( 都 腔)腔URL( 眈骯佼 !) STDOUT懷堤

:
RewriteEngine on
RewriteMap quux-map prg:/path/to/map.quux.pl
RewriteRule ^/~quux/(.*)$ /~quux/${quux-map:$1}


:
#!/path/to/perl

# disable buffered I/O which would lead
# to deadloops for the Apache server
$| = 1;

# read URLs one per line from stdin and
# generate substitution URL on stdout
while (<>) {
s|^foo/|bar/|;
print $_;
}

跺 栳 腔瞰 ㄛ硐 衄腔URL /~quux/foo/... /~quux/bar/...ㄛ 岈妗 ㄛ褫 坳黨蜊 腕?睡 猁腔髡夔 猁 砩ㄛ ? 啜 褫 ㄛ褫 硐衄 符褫 隅 腔




  • 贊助網站       

    廣利不動產-板橋在地生根最實在--新板特區指名度最高、值得您信賴的好房仲
    完整房訊,房屋、店面熱門精選物件,廣利不動產 優質仲介,房屋租賃、買賣資訊透明,交易真安心!
    廣利不動產-新板特區指名度最高、值得您信賴的好房仲
    您的托付,廣利用心為您服務



  •  共 0 人回應

    姓名:
    佈告內容:
    其他選項: