Tomcat 重寫機(jī)制

2022-03-03 14:09 更新

簡(jiǎn)介

重寫 Valve(Rewrite Valve) 實(shí)現(xiàn) URL 重寫功能的方式非常類似于 Apache HTTP Server 的 mod_rewrite 模塊。

配置

重寫 Valve 是通過(guò)使用 org.apache.catalina.valves.rewrite.RewriteValve 類名來(lái)配置成 Valve 的。

經(jīng)過(guò)配置,重寫 Valve 可以做為一個(gè) Valve 添加到 Host 中。參考虛擬服務(wù)器文檔來(lái)了解配置詳情。該 Valve 使用包含重寫指令的 rewrite.config 文件,且必須放在 Host 配置文件夾中。

另外,重寫 valve 也可以用在 Web 應(yīng)用的 context.xml 中。該 Valve 使用包含重寫指令的 rewrite.config 文件,且必須放在 Web 應(yīng)用的 WEB-INF 文件夾中。

指令

rewrite.config 文件包含一系列指令,這些指令和 mod_rewrite 所用的指令很像,尤其是核心的 RewriteRuleRewriteCond 指令。

注意:該部分內(nèi)容修改自 mod_rewrite 文檔,后者版權(quán)歸屬于 Apache 軟件基金會(huì)(1995-2006),遵循 Apache 許可發(fā)布。

1. RewriteCond

格式:RewriteCond TestString CondPattern

RewriteCond 指令定義了一個(gè)規(guī)則條件。一個(gè)或多個(gè) RewriteCond 指令可以優(yōu)先于 RewriteRule 指令執(zhí)行。如果 URI 當(dāng)前狀態(tài)匹配它的模式,并且滿足了這些條件,才會(huì)使用下列規(guī)則。

TestString 是一種字符串,除了簡(jiǎn)單的文本之外,它還可以含有下列擴(kuò)展結(jié)構(gòu)。

  • RewriteRule backreferences 對(duì)形式 $N(0 <= N <= 9)的反向引用。提供對(duì)模式成組部分的訪問(wèn)(括號(hào)中的),從屬于 RewriteCond 條件當(dāng)前狀態(tài)的 RewriteRule。
  • RewriteCond backreferences
  • RewriteMap expansions
  • Server-Variables 這些是形式 %{ NAME_OF_VARIABLE } 中的變量。%{ NAME_OF_VARIABLE } 中的 NAME_OF_VARIABLE 是一種取自下面列表的字符串:

  • HTTP 報(bào)頭
HTTP\_USER\_AGENT  
HTTP\_REFERER  
HTTP\_COOKIE  
HTTP\_FORWARDED  
HTTP\_HOST  
HTTP\_PROXY\_CONNECTION  
HTTP\_ACCEPT    
  • 連接與請(qǐng)求
REMOTE\_ADDR  
REMOTE\_HOST  
REMOTE\_PORT  
REMOTE\_USER  
REMOTE\_IDENT  
REQUEST\_METHOD  
SCRIPT\_FILENAME  
REQUEST\_PATH  
CONTEXT\_PATH  
SERVLET\_PATH  
PATH\_INFO  
QUERY\_STRING  
AUTH\_TYPE  
  • 服務(wù)器內(nèi)部
DOCUMENT\_ROOT    
SERVER\_NAME  
SERVER\_ADDR  
SERVER\_PORT  
SERVER\_PROTOCOL  
SERVER\_SOFTWARE  
  • 日期與時(shí)間
TIME\_YEAR  
TIME\_MON  
TIME\_DAY  
TIME\_HOUR  
TIME\_MIN  
TIME\_SEC  
TIME\_WDAY  
TIME 
  • 特殊字符串
THE\_REQUEST  
REQUEST\_URI  
REQUEST\_FILENAME  
HTTPS     

這些變量對(duì)應(yīng)著相似名稱的 HTTP MIME 報(bào)頭和 Servlet API 方法。多數(shù)都記錄在各種手冊(cè)和 CGI 規(guī)范中。下面列出了重寫 Valve 專有的那些變量:

  • REQUEST_PATH
    對(duì)應(yīng)用于映射的完整路徑。
  • CONTEXT_PATH
    對(duì)應(yīng)映射的上下文的路徑。
  • SERVLET_PATH
    對(duì)應(yīng) Servlet 路徑。
  • THE_REQUEST
    由瀏覽器發(fā)送給服務(wù)器的完整 HTTP 請(qǐng)求代碼行(比如,GET /index.html HTTP/1.1)。這并不包括任何由瀏覽器發(fā)送的額外報(bào)頭。
  • REQUEST_URI
    HTTP 請(qǐng)求代碼行中所請(qǐng)求的資源(在上例中,應(yīng)為為 /index.html)。
  • REQUEST_FILENAME
    與請(qǐng)求相匹配的文件或腳本的完整本地文件系統(tǒng)路徑。
  • HTTPS
    當(dāng)連接使用 SSL/TLS 時(shí),含有文本 "on",否則含有 "off"

另外還需要注意的是:

  1. SCRIPT_FILENAMEREQUEST_FILENAME 含有同樣的值:Apache 服務(wù)器內(nèi)部結(jié)構(gòu) request_recfilename 字段值。第一個(gè)名稱常被稱為 CGI 變量值,第二個(gè)名稱相當(dāng)于 REQUEST_URI(包含 request_recuri 字段值)。
  2. %{ENV:variable}。其中的 variable 可以是任何 Java 系統(tǒng)屬性。目前可以使用。
  3. %{SSL:variable}。其中的 variable 是 SSL 環(huán)境變量名。目前還未實(shí)現(xiàn)。范例: %{SSL:SSL_CIPHER_USEKEYSIZE} 可能擴(kuò)展到 128
  4. %{HTTP:header}。其中的 header 可以是任意的 HTTP MIME 報(bào)頭名稱。該變量常用來(lái)獲取發(fā)送到 HTTP 請(qǐng)求的報(bào)頭值。范例: %{HTTP:Proxy-Connection} 是 HTTP 報(bào)頭 Proxy-Connection: 的值。

CondPattern 即條件模式,是一種應(yīng)用于 TestString 當(dāng)前實(shí)例的正則表達(dá)式。TestString 在匹配 CondPattern 之前,會(huì)首先求值。

謹(jǐn)記CondPattern 是一種兼容 perl 并帶有一些擴(kuò)展的正則表達(dá)式。

  1. 可以在模式字符串前加上 ! 字符作為前綴,來(lái)指定匹配模式。
  2. CondPattern 有一些特殊變體。除了真正的正則表達(dá)式字符串外,還可以使用下列組合形式之一:
    • <CondPattern (字母順序高于)
      CondPattern 當(dāng)成一種純粹字符串,按照字母順序?qū)⑵渑c TestString 進(jìn)行對(duì)比。如果在字母順序上,TestString 高于 CondPattern ,則為 true。
    • >CondPattern(字母順序低于)將 CondPattern 當(dāng)成一種純粹字符串,按照字母順序?qū)⑵渑c TestString 進(jìn)行對(duì)比。如果在字母順序上,TestString 低于 CondPattern ,則為 true。
    • =CondPattern' (字母順序等于)
      CondPattern 當(dāng)成一種純粹字符串,按照字母順序?qū)⑵渑c TestString 進(jìn)行對(duì)比。如果在字母順序上,TestString 等于 CondPattern ,則為 true。
    • -d(目錄)
      TestString 當(dāng)成一種路徑名,測(cè)試它是否存在并且是一個(gè)目錄。
    • -f(常規(guī)文件)將 TestString 當(dāng)成一種路徑名,測(cè)試它是否存在并且是一個(gè)常規(guī)文件。
    • -s(常規(guī)文件,帶有文件尺寸)
      TestString 當(dāng)成一種路徑名,測(cè)試它是否存在并且是一個(gè)文件大小大于 0 的普通文件。

注意:所有這些測(cè)試都可以加上前綴 ! 來(lái)使它們的含義反向。

  1. 可以將 [flag] 做為 RewriteCond 指令的第三個(gè)參數(shù),為 CondPattern 設(shè)定標(biāo)記。這里的 flag 是一個(gè)包含下列任一標(biāo)記,且標(biāo)記間由逗號(hào)分隔的列表:
    • nocase|NC(不區(qū)分大小寫)無(wú)論是擴(kuò)展的 TestString 還是在 CondPattern 中,都不區(qū)分大小寫(A-Z 和 a-z 是等同的)。該標(biāo)記只有在比較 TestStringCondPattern 時(shí)才是有效的。對(duì)于文件系統(tǒng)和子請(qǐng)求(HTTP 請(qǐng)求)是無(wú)效的。
    • ornext|OR(或者下一個(gè)條件)利用本地 OR(而不是隱式的 AND)來(lái)組合規(guī)則條件。典型范例為:
RewriteCond %{REMOTE_HOST}  ^host1.*  [OR]  
RewriteCond %{REMOTE_HOST}  ^host2.*  [OR]  
RewriteCond %{REMOTE_HOST}  ^host3.*  
RewriteRule ...some special stuff for any of these hosts...       

沒(méi)有該標(biāo)記,你必須寫三遍條件/規(guī)則對(duì)。

范例

假如想根據(jù)請(qǐng)求頭的 User-Agent: 對(duì)網(wǎng)站主頁(yè)進(jìn)行重寫,可以使用下列代碼:

RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
RewriteRule  ^/$                 /homepage.max.html  [L]

RewriteCond  %{HTTP_USER_AGENT}  ^Lynx.*
RewriteRule  ^/$                 /homepage.min.html  [L]

RewriteRule  ^/$                 /homepage.std.html  [L]

說(shuō)明:如果使用的瀏覽器將它自身標(biāo)識(shí)為 'Mozilla'(包括 Netscape Navigator、Mozilla,等等),那么這就是內(nèi)容最大化主頁(yè)(max homepage。它可以包含框架或其他特性);如果使用的是 Lynx 瀏覽器(基于終端的),那么獲得的就是內(nèi)容最小化的主頁(yè)(min homepage)——專為便于瀏覽文本而設(shè)計(jì)的版本;如果這些條件都不適用(你使用的是其他瀏覽器,或者你的瀏覽器將其自身標(biāo)識(shí)為非標(biāo)準(zhǔn)內(nèi)容),那么得到的就是標(biāo)準(zhǔn)主頁(yè)(std homepage)。

2. RewriteMap

格式:RewriteMap name rewriteMapClassName optionalParameters

通過(guò)用戶必須實(shí)現(xiàn)的一個(gè)接口來(lái)實(shí)現(xiàn)映射。類名為 org.apache.catalina.valves.rewrite.RewriteMap,代碼為:

package org.apache.catalina.valves.rewrite;

public interface RewriteMap {
public String setParameters(String params);
public String lookup(String key);
}

3. RewriteRule

格式:RewriteRule Pattern Substitution

RewriteRule 指令是重寫機(jī)制的核心。此指令可以多次使用,每個(gè)實(shí)例都定義一個(gè)單獨(dú)的重寫規(guī)則。這些規(guī)則的定義順序尤為重要,因?yàn)檫@是在運(yùn)行時(shí)應(yīng)用它們的順序。

模式是一個(gè)作用于當(dāng)前 URL 的兼容 perl 的正則表達(dá)式,這里的“當(dāng)前”是指該規(guī)則生效時(shí)的 URL,它可能與被請(qǐng)求的 URL 不同,因?yàn)槠渌?guī)則可能在此之前已經(jīng)發(fā)生匹配并對(duì)它做了改動(dòng)。

下面是關(guān)于正則表達(dá)式格式的一些提示:

文本

  • .——匹配任何單個(gè)字符
  • [chars]——匹配當(dāng)前字符
  • [^chars]——不匹配當(dāng)前字符
  • text1|text2——匹配 text1 或 text2

量詞:

  • ?——零個(gè)或者 1 個(gè) ? 號(hào)前的字符
  • *——零個(gè)或者 N 個(gè) * 號(hào)前的字符(N > 0)
  • +——零個(gè)或 N 個(gè) + 號(hào)前的字符(N > 1)

分組(text)——文本分組(設(shè)定第 N 組可以被引用為 RewriteRule)


行錨

^——匹配一行起始處的空字符串。
$——匹配一行結(jié)束處的空字符串。


轉(zhuǎn)義

\char ——將指定字符轉(zhuǎn)義(比如將.[]、() 等字符轉(zhuǎn)義)

要想了解更多關(guān)于正則表達(dá)式的信息,請(qǐng)參見(jiàn) perl 正則表達(dá)式在線聯(lián)機(jī)手冊(cè)(perldoc perlre)。關(guān)于正則表達(dá)式及其變體(POSIX 正則表達(dá)式)的詳情,可看看這本書:

*Mastering Regular Expressions, 2nd Edition* (目前該書為第 3 版)
Jeffrey E.F. Friedl 
O'Reilly & Associates, Inc. 2002
ISBN 978-0-596-00289-3  

在規(guī)則中,NOT 字符(!)可作為模式的前綴,實(shí)現(xiàn)逆向模式。比如“如果當(dāng)前 URL 并匹配該模式”。這可以用在易于匹配的是逆向模式這種異常情況下,或者也可以作為最后一個(gè)默認(rèn)規(guī)則來(lái)使用。

注意:在使用 NOT 字符反轉(zhuǎn)模式時(shí),不能在模式中包含分組的通配成分。這是因?yàn)?,如果模式不匹配(比如反匹配),分組內(nèi)將沒(méi)有內(nèi)容。如果使用了逆向模式,就不能在替代字符串中使用 $N

重寫規(guī)則中的替代字符串(substitution string)是一種用來(lái)取代模式匹配的原始 URL 的字符串。除了純文本之外,它還包括:

  1. 反向引用($N)RewriteRule 模式。
  2. 反向引用(%N)最后匹配的 RewriteCond 模式。
  3. 規(guī)則條件測(cè)試字符串中(%{VARNAME})的服務(wù)器變量。
  4. 映射函數(shù)調(diào)用(${mapname:key|default})。

反向引用表示的是形式 $N(N 的范圍為 0-9),它是指用模式所匹配的第 N 組的內(nèi)容去替換 URL。服務(wù)器變量 RewriteCond 指令的 TestString 所用的相同。映射函數(shù)來(lái)自 RewriteMap 指令。這 3 類變量都按照上述順序展開(kāi)。

如前所述,所有的重寫規(guī)則都應(yīng)用于替代字符串(按照配置文件中所定義的順序)。URL 完全由替代字符串所替換,直到所有規(guī)則都應(yīng)用完畢,重寫過(guò)程才結(jié)束(或利用 L 標(biāo)記來(lái)終止)。

還有一個(gè)特殊的替代字符串:-,意思是不替代,當(dāng)需要讓重寫規(guī)則只匹配 URL 而不替換時(shí),就用得上它了。這一字符串通常與 C(chain)標(biāo)記配合使用,為的是在替換發(fā)生前應(yīng)用多個(gè)模式。

另外,還可以將 [flags] 做為 RewriteRule 的第三個(gè)參數(shù),從而為替代字符串設(shè)置特殊標(biāo)記。flags是一個(gè)包含下列標(biāo)記且標(biāo)記間以逗號(hào)分隔的列表:

  • chain|C (與下一個(gè)規(guī)則相鏈接)

此標(biāo)記使當(dāng)前規(guī)則與下一個(gè)規(guī)則(它又可以與其后規(guī)則相鏈接,如此反復(fù))相鏈接。 它產(chǎn)生如下效果:如果某個(gè)規(guī)則被匹配,通常會(huì)繼續(xù)處理其后繼規(guī)則,這個(gè)標(biāo)記就不起作用;如果某規(guī)則不被匹配,則其后繼鏈接規(guī)將會(huì)被忽略。比如,在執(zhí)行一個(gè)外部重定向時(shí), 對(duì)一個(gè)目錄級(jí)規(guī)則集,你可能需要?jiǎng)h除 .www(因?yàn)榇颂幉粦?yīng)該出現(xiàn) .www)。

  • cookie|CO = NAME:VAL:domain[:lifetime[:path]] (設(shè)置 cookie)

在客戶端瀏覽器上設(shè)置一個(gè) cookie。cookie 的名稱是 NAME,其值是 VAL。 domain 字段是該 cookie 的域,比如 .apache.org,可選的lifetime 是 cookie 生命周期(以分鐘計(jì)),可選的 path 是 cookie 的路徑。

  • env|E = VAR:VAL (設(shè)置環(huán)境變量)

強(qiáng)制一個(gè)名為 VAR 的請(qǐng)求變量值為 VAL,VAL可以包含可擴(kuò)展的反向引用的正則表達(dá)式 $N%N??梢远啻问褂迷摌?biāo)記,以便設(shè)置多個(gè)變量。

  • forbidden|F(強(qiáng)制禁止訪問(wèn)該 URL )

強(qiáng)制禁止訪問(wèn)當(dāng)前的 URL——立即反饋一個(gè) HTTP 響應(yīng)代碼 403。使用這個(gè)標(biāo)記,可以鏈接若干 RewriteConds 以阻斷某些 URL。

  • gone|G(強(qiáng)制 URL 為已失效)

強(qiáng)制當(dāng)前 URL 為已失效——立即反饋一個(gè) HTTP 響應(yīng)代碼 410(請(qǐng)求資源已被刪除)。使用這個(gè)標(biāo)記,可以標(biāo)明頁(yè)面已被刪除而不存在.

  • host|H=Host(重寫虛擬主機(jī))
    重寫虛擬主機(jī),而不是重寫 URL。

  • last|L(最后一個(gè)規(guī)則)

立即停止重寫操作,并不再應(yīng)用其他重寫規(guī)則。它對(duì)應(yīng)于 Perl 中的 last 命令或 C 語(yǔ)言中的 break 命令。使用該標(biāo)記可以防止當(dāng)前已被重寫的 URL 被后續(xù)規(guī)則所繼續(xù)重寫。比如,用它可以將根路徑的 URL(/)重寫為實(shí)際存在的 URL,比如:/e/www/。

  • next|N(重新執(zhí)行)

重新執(zhí)行重寫操作(從第一個(gè)重寫規(guī)則重新開(kāi)始)。這時(shí),要匹配的 URL 已不是原始 URL 了,而是經(jīng)最后一個(gè)重寫規(guī)則處理過(guò)的 URL。它對(duì)應(yīng)于 Perl 中的 next 命令或 C 語(yǔ)言中的 continue 命令。此標(biāo)記可以重新開(kāi)始重寫操作,立即回到循環(huán)的頭部。

但是要小心,不要制造死循環(huán)!

  • nocase|NC(不區(qū)分大小寫)

使模式不區(qū)分大小寫。當(dāng)模式與當(dāng)前 URL 匹配時(shí),A-Z 和 a-z 沒(méi)有區(qū)別。

  • noescape|NE(在輸出中不對(duì) URI 進(jìn)行轉(zhuǎn)義)

此標(biāo)記阻止重寫 Valve 對(duì)重寫結(jié)果應(yīng)用常規(guī)的 URI 轉(zhuǎn)義規(guī)則。一般情況下,特殊字符(如%$、;等)都會(huì)被轉(zhuǎn)義為十六進(jìn)制值。此標(biāo)記可以阻止這種轉(zhuǎn)義,允許百分號(hào)等符號(hào)出現(xiàn)在輸出中,如:

RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]

/foo/zed 轉(zhuǎn)化為 /bar?arg=P1=zed 的安全請(qǐng)求。

  • qsappend|QSA(附加查詢串)

該標(biāo)記會(huì)強(qiáng)制重寫引擎將替代字符串中的一個(gè)查詢字符串部分添加到已有字符串上,而不是簡(jiǎn)單地替換已有字符串。當(dāng)你想要通過(guò)重寫規(guī)則為查詢字符串添加更多數(shù)據(jù)時(shí),可以使用該標(biāo)記。

  • redirect|R[=code](強(qiáng)制重定向)

http://thishost[:thisport]/(使新的 URL 成為一個(gè) URI)作為替代字符串的前綴,從而強(qiáng)制執(zhí)行一個(gè)外部重定向。如果沒(méi)有指定 code,則產(chǎn)生一個(gè)HTTP 響應(yīng)代碼 302(暫時(shí)移動(dòng))。如果需要使用在 300-400 范圍內(nèi)的其他響應(yīng)代碼,只需在此指定這個(gè)數(shù)值即可。另外,還可以使用下列符號(hào)名稱:temp(默認(rèn)),permanent、seeother。用它可以把規(guī)范化的 URL 反饋給客戶端,如重寫 /~/u/,或?qū)?code>/u/user 加上斜杠,等等。

注意:在使用這個(gè)標(biāo)記時(shí),必須確保替換字段是一個(gè)有效的 URL!否則它會(huì)指向一個(gè)無(wú)效的位置!并且要記住,此標(biāo)記本身只是對(duì) URL 加上 http://thishost[:thisport]/ 前綴而已,不會(huì)妨礙重寫操作。通常,你會(huì)希望停止重寫,然后立即重定向。要想停止重寫,你還需要添加 L 標(biāo)記。

  • skip|S=num(忽略后續(xù)規(guī)則)

如果當(dāng)前規(guī)則匹配,此標(biāo)記會(huì)強(qiáng)制重寫引擎跳過(guò)當(dāng)前匹配規(guī)則后面的 num 個(gè)規(guī)則。它可以實(shí)現(xiàn)一個(gè)類似 if-then-else 的構(gòu)造:then 子句的最后一個(gè)規(guī)則是 skip = N,其中 N 代表 else 子句中的規(guī)則數(shù)目。(該標(biāo)記不同于chain|C 標(biāo)記?。?/p>

  • type|T=MIME-type(強(qiáng)制指定 MIME 類型)

強(qiáng)制指定目標(biāo)文件的 MIME 類型為 MIME-type,可基于一些條件設(shè)置內(nèi)容類型。比如在下面的代碼段中,如果利用 .phps 擴(kuò)展調(diào)用 .php 文件,它們就能被 mod_php 模塊顯示。

RewriteRule ^(.+\.php)s$ $1 [T=application/x-httpd-php-source]

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)