Apache使用 RewriteMap

2019-10-16 22:02:12

本文描述了RewriteMap指令的使用,並提供了各種RewriteMap型別的範例。

RewriteMap指令定義了一個外部函式,可以在RewriteRuleRewriteCond指令的上下文中呼叫它來執行過於複雜的重寫,或者太專業化而不能僅通過正規表示式執行。

RewriteMap指令的語法如下:

RewriteMap MapName MapType:MapSource

對映名稱是您為對映指定的任意名稱,稍後將在指令中使用該名稱。引數通過以下語法傳遞給對映:

${ MapName : LookupKey } 
${ MapName : LookupKey | DefaultValue }

當發生這樣的構造時,查詢對映MapName並查詢LookupKey鍵。如果找到此鍵,則map-function構造將由SubstValue替換。如果未找到鍵,則如果未指定DefaultValue,則將其替換為DefaultValue或空字串。

例如,可以將RewriteMap定義為:

RewriteMap examplemap "txt:/path/to/file/map.txt"

然後,可以在RewriteRule中使用此對映,如下所示:

RewriteRule "^/ex/(.*)" "${examplemap:$1}"

如果在對映中找不到任何內容,則可以指定預設值:

RewriteRule "^/ex/(.*)" "${examplemap:$1|/not_found.html}"

int:內部函式

當使用intMapType時,MapSource是可用的內部RewriteMap函式之一。模組作者可以通過使用ap_register_rewrite_mapfunc API註冊它們來提供其他內部函式。預設提供的功能是:

  • toupper:將鍵全部轉換為大寫。
  • tolower:將鍵全部轉換為小寫。
  • escape:將鍵中的特殊字元轉換為十六進位制編碼。
  • unescape:將鍵中的十六進位制編碼轉換回特殊字元。

將URI重定向到自身的全小寫版本 -

RewriteMap lc int:tolower
RewriteRule "(.*)" "${lc:$1}" [R]

txt:純文字對映

當使用txt的MapType時,MapSource是純文字對映檔案的檔案系統路徑,每行包含一個以空格分隔的鍵/值對。可選地,一行可以包含以#字元開頭的注釋。

有效的文字重寫對映檔案具有以下語法:

# Comment line
MatchingKey SubstValue
MatchingKey SubstValue # comment

呼叫RewriteMap時,將在行的第一個引數中查詢引數,如果找到則返回替換值。

例如,可以使用mapfile將產品名稱轉換為產品ID,以便更容易記住URL,使用以下配方:

產品到ID組態如下 -

RewriteMap product2id "txt:/etc/apache2/productmap.txt"
RewriteRule "^/product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

rnd:隨機化純文字

當使用Rnd的MapType時,MapSource是純文字對映檔案的檔案系統路徑,每行包含一個鍵,一個或多個值以|分隔。如果鍵匹配,將隨機選擇其中一個值。

例如,您可以使用以下對映檔案和指令通過反向代理在多個後端伺服器之間提供隨機負載平衡。影象被傳送到「靜態」池中的一個伺服器,而其他所有內容都被傳送到「動態」池中的一個。

Rewrite map file
##
## map.txt -- rewriting map
##

static www1|www2|www3|www4
dynamic www5|www6

組態的指令如下 -

RewriteMap servers "rnd:/path/to/file/map.txt"

RewriteRule "^/(.*\.(png|gif|jpg))" "http://${servers:static}/$1"  [NC,P,L]
RewriteRule "^/(.*)"                "http://${servers:dynamic}/$1" [P,L]

因此,當請求影象並且第一個規則匹配時,RewriteMap會在map檔案中查詢字串static,它會隨機返回一個指定的主機名,然後在RewriteRule目標中使用。

如果希望更有可能選擇其中一個伺服器(例如,如果其中一個伺服器的記憶體多於其他伺服器,因此可以處理更多請求),只需在對映檔案中列出更多次。

static www1|www1|www2|www3|www4

dbm:DBM雜湊檔案

當使用dbm的MapType時,MapSource是DBM資料庫檔案的檔案系統路徑,該檔案包含要在對映中使用的鍵/值對。這與txt對映的工作方式完全相同,但速度要快得多,因為DBM是索引的,而文字檔案則不是。這允許更快速地存取所需的金鑰。

可以選擇指定特定的dbm型別:

RewriteMap examplemap "dbm=sdbm:/etc/apache/mapfile.dbm"

型別可以是sdbmgdbmndbmdb。但是,建議您只使用Apache HTTP Server提供的httxt2dbm實用程式,因為它將使用正確的DBM庫,與構建httpd本身時使用的庫匹配。

要建立dbm檔案,請首先按照txt部分中的說明建立文字對映檔案。然後執行httxt2dbm

$ httxt2dbm -i mapfile.txt -o mapfile.map

然後,可以在RewriteMap指令中參照生成的檔案:

RewriteMap mapname "dbm:/etc/apache/mapfile.map"

prg:外部重寫程式

當使用prg的MapType時,MapSource是可執行程式的檔案系統路徑,該程式將提供對映行為。這可以是編譯的二進位制檔案,也可以是Perl或Python等解釋語言的程式。

當Apache HTTP Server啟動時,該程式啟動一次,然後通過STDIN和STDOUT與重寫引擎通訊。也就是說,對於每個對映函式查詢,它通過STDIN期望一個引數,並且應該在STDOUT上返回一個新行終止的響應字串。如果沒有相應的查詢值,則對映程式應返回四個字元的字串「NULL」以指示此情況。

如果在沒有將RewriteEngine設定為on的上下文中定義外部重寫程式,則不會啟動外部重寫程式。

預設情況下,外部重寫程式作為使用者:啟動httpd的組執行。這可以在UNIX系統上通過將使用者名和組名作為第三個引數以username:groupname格式傳遞給RewriteMap來更改。

此功能使用重寫對映互斥鎖,這是與程式可靠通訊所必需的。可以使用Mutex指令組態互斥鎖機制和鎖定檔案。

這裡顯示了一個簡單的範例,它將替換請求URI中帶下劃線的所有破折號。

重寫組態如下 -

RewriteMap d2u "prg:/www/bin/dash2under.pl" apache:apache
RewriteRule "-" "${d2u:%{REQUEST_URI}}"

dash2under.pl

#!/usr/bin/perl
$| = 1; # Turn off I/O buffering
while (<STDIN>) {
    s/-/_/g; # Replace dashes with underscores
    print $_;
}

dbd或fastdbd:SQL查詢

使用dbd或fastdbd的MapType時,MapSource是一個SQL SELECT語句,它接受單個引數並返回單個值。

需要將mod_dbd組態為指向正確的資料庫以執行此語句。

這種MapType有兩種形式。使用dbd的MapType會導致查詢與每個對映請求一起執行,而使用fastdbd會在內部快取資料庫查詢。因此,雖然fastdbd更高效,因此更快,但在重新啟動伺服器之前,它不會接受對資料庫的更改。

如果查詢返回多行,則使用結果集中的隨機行。

範例:

RewriteMap myquery "fastdbd:SELECT destination FROM rewrite WHERE source = %s"