<-
Apache > HTTP 伺服器 > 文件 > 版本 2.4 > 重寫

使用 RewriteMap

提供的語系:  en  |  fr 

此文件補充 mod_rewrite 參考文件。它說明 RewriteMap 指令的用法,並提供範例說明每種類型的 RewriteMap

請注意,這些範例有許多在您特定的伺服器設定中無法變更,因此,理解他們很重要,而非僅將範例貼到您的設定中。
Support Apache!

請另見

top

引言

RewriteRuleRewriteCond 指令的架構中可呼叫 RewriteMap 指令定義的外部函數,以進行太複雜或太特殊,單單以正規表示式無法執行的重寫作業。此查詢的來源可以是下方各節所列的類型,或列於 RewriteMap 參考文件的類型。

以下是 RewriteMap 指令的語法

RewriteMap MapName MapType:MapSource

您所指定指定的地圖任意名稱為 MapName,您將在後續指令中使用此名稱。參數透過下列語法傳遞至地圖

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

當出現這樣的建構時,系統會檢閱地圖 MapName 然後查詢金鑰 LookupKey。如果找到金鑰,會用 SubstValue 取代地圖功能建構。如果找不到金鑰,則會用 DefaultValue 取代,如果沒有指定 DefaultValue,則會用空字串取代。

例如,您可以定義 RewriteMap

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

然後您便可以在 RewriteRule 中使用這個地圖,如下所示

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

如果在映射中找不到任何東西,則可以指定預設值

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

每目錄及 .htaccess 情境

無法在 RewriteMap 指令中使用 <Directory> 區段或 .htaccess 檔案。您必須在伺服器或虛擬主機環境中宣告這個映射。在建立映射之後,您可以在這些範圍中,在您的 RewriteRule 以及 RewriteCond 指令中使用這個映射。不過您無法在這些範圍中**宣告**它。

以下各節將說明可以使用的各種 MapType,並提供各類型的範例。

top

int:內部函式

當使用 int 的 MapType 時,MapSource 是其中一個可用的內部 RewriteMap 函式。模組作者可以使用 ap_register_rewrite_mapfunc API 註冊額外內部函數。預設提供的函式為

如要使用其中一個函式,請建立一個引用 int 函式的 RewriteMap,然後在 RewriteRule 中使用該映射。

將 URI 重新導向至其全小寫版本

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

請注意,這裡提供的範例僅供說明用途,並不構成建議。如果您想要讓 URL 不分大小寫,請考慮改用 mod_speling

top

txt:純文字映射

當使用 txt 的 MapType 時,MapSource 是純文字對應檔案的檔案系統路徑,其中每列包含一個以空格分隔的金鑰/值對。有時候,列可能包含註解,以「#」字元開頭。

有效的文字重新寫入對應檔案將具有以下語法

#註解列
相符金鑰 取代值
相符金鑰 取代值 # 註解

當呼叫 RewriteMap 時,會在第一個參數行中尋找參數,如果找到,會傳回取代值。

例如,我們可以使用 mapfile 將產品名稱轉換為產品 ID,以便更輕鬆地記住 URL,如下食譜所示

產品對 ID 設定

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

這裡我們假設 `prods.php` 指令碼知道在查詢對應表中找不到產品時,收到 `id=NOTFOUND` 參數時該怎麼辦。

檔案 `/etc/apache2/productmap.txt` 然後包含下列內容

產品對 ID 對應表

##
## productmap.txt - 產品對 ID 對應表檔
##

television 993
stereo 198
fishingrod 043
basketball 418
telephone 328

因此,當要求 `http://example.com/product/television` 時,會套用 RewriteRule,並將要求內部對應到 `prods.php?id=993`。

注意:.htaccess 檔案

提供的範例會在伺服器或虛擬主機範圍內使用。如果您計畫在 `htaccess` 檔案中使用它,您必須從重寫樣板中移除開頭的斜線,才能與任何項目相符
RewriteRule "^product/(.*)" "/prods.php?id=${product2id:$1|NOTFOUND}" [PT]

快取查詢

查詢金鑰會由 httpd 快取,直到 mapfile 的 `mtime` (修改時間) 變更,或 httpd 伺服器重新啟動。這可以確保在許多要求呼叫的對應表上,有更好的效能。

top

rnd:隨機純文字

當使用 `rnd` 的 MapType 時,MapSource 是平文件對應表檔案的檔案系統路徑,其每一行都包含一個金鑰,以及一個或多個由 `|` 分隔的值。如果金鑰相符,其中一個值將隨機選取。

例如,您可以使用下列對應表檔案和指令,透過反向代理在多個後端伺服器之間提供隨機負載平衡。圖像會傳送到「static」池中的其中一個伺服器,而其他所有內容會傳送到「dynamic」池中的其中一個伺服器。

重寫對應表檔

##
## map.txt -- 重寫對應表
##

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 會在對應表檔案中查詢字串 `static`,它會隨機傳回指定的其中一個主機名稱,然後在 RewriteRule 目標中使用。

如果您希望其中一台伺服器更有可能被選取(例如,如果其中一台伺服器比其他伺服器有更多記憶體,因此可以處理更多要求),只要在對應表檔案中列出更多次即可。

靜態 www1|www1|www2|www3|www4

top

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"

請注意,對於某些 dbm 類型,會產生多個檔案,且具有共同的基礎檔名。例如,你可能會有兩個名為 mapfile.map.dirmapfile.map.pag 的檔案。這是正常的,你只要在 RewriteMap 指示中使用基礎檔名 mapfile.map 即可。

快取查詢

查詢金鑰會由 httpd 快取,直到 mapfile 的 `mtime` (修改時間) 變更,或 httpd 伺服器重新啟動。這可以確保在許多要求呼叫的對應表上,有更好的效能。

top

prg:外部重寫程式

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

此程式在 Apache HTTP Server 啟動時啟動一次,然後透過 STDINSTDOUT 與重寫引擎通訊。也就是說,對於每個對應函數查詢,它都透過 STDIN 接收一個引數,並且應該在 STDOUT 上傳回一個換行終止的回應字串。如果沒有對應的查詢值,對應程式應傳回四個字母的字串「NULL」以表示這一點。

如果外部重寫程式是在未設定 RewriteEngineon 的內容中定義,則不會啟動這些程式。

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

此功能使用 rewrite-map mutex,這對於與程式可靠通訊是必要的。mutex 機制和鎖定檔案可以使用 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 $_;
}

小心!

  • 盡可能簡化重寫對應程序。如果程序當掉,會導致 httpd 無限期地等待對應的回應,而這反過來又會導致 httpd 停止回應要求。
  • 務必在程序中關閉緩衝。在 Perl 中,這是藉由範例腳本中的第二行來完成:`$| = 1;` 當然,這在其他語言中會有不同。緩衝 I/O 會導致 httpd 等待輸出的結果,因此它會當掉。
  • 請記住,只有一個程序副本會在伺服器啟動時啟動。所有要求都需要通過這個瓶頸。如果很多要求必須經過這個程序,或者如果腳本本身很慢,可能會導致速度大幅下降。
top

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"

注意事項

查詢名稱會傳遞給資料庫驅動程式作為 SQL 準備陳述式的標籤,因此需要遵循資料庫要求的所有規則(例如區分大小寫)。

top

摘要

RewriteMap 指令可以出現多次。對於每個對應函數,請使用一個 RewriteMap 指令來宣告其重寫對應檔案。

儘管你無法在目錄中宣告對應(`.htaccess` 檔案或 <Directory> 區塊),但有可能在目錄中使用這個對應。

提供的語系:  en  |  fr 

top

意見

注意
這裡不是問答區段。在這裡張貼的留言應該是針對改善文件或伺服器的建議,如果它們已被實作或被認為無效/離題,可能會被我們的管理員移除。有關如何管理 Apache HTTP Server 的問題應 направляться至我們在 Libera.chat 上的 IRC 頻道 #httpd,或傳送至我們的 郵件列表