rewrite[伺服器重寫技術]

Rewrite是一種伺服器的重寫技術,它可以使得伺服器可以支持 URL 重寫,是一種最新流行的伺服器技術。它還可以實現限制特定IP訪問網站的功能。

Rewrite介紹

很多情況下,某個 IP 的訪問很容易造成 CPU 100% (比如 某些搜尋引擎的固定抓取,別人大量的採集站點),這個時候我們就要利用一些有效的手段封掉對方的 IP,讓他無法消耗伺服器的資源,封 IP 的方法有很多種,如果你的 Web 伺服器安裝了 Rewrite 模組的話,也可以試試利用 Rewrite 規則封掉對方的 IP。

例如我們把某個特定的 IP 直接重定向到 baidu 首頁,在網站根目錄的 .htaccess 檔案里添加代碼:

Code:

RewriteCond % 123.123.123.123 [NC]

RewriteRule ^(.*)$ http://www.baidu.com/$1 [R=301]

將 123.123.123.123 這個 IP 替換成您要限制的 IP 即可。如果要實現多個 IP ,可以這樣寫:

RewriteCond % 123.123.123.123 [OR]

RewriteCond % 124.124.124.124 [NC]

RewriteRule ^(.*)$ http://www.baidu.com/$1 [R=301]

Rewrite主要的功能

Rewrite主要的功能就是實現URL的重寫。它的正則表達式是基於Perl語言,入站的規則用於修改 HTTP 請求 Url。這些規則可以為以下幾個目的,如演示對用戶更加友好的 URL 命名空間為您的 Web 站點,將請求的 Url 重定向到新位置,或阻止訪問 Url 來提供服務。出站的重寫規則修改 HTTP 回響。例如,如果您的 Web 站點的導航結構已更改,您可以創建修改您的內容中的 Url,以便將 Web 頁的內容指向正確的位置出站規則。然後,您可以創建基於快取的位置與新的 url 的客戶端請求重定向的入站的規則。可基於伺服器級的(httpd.conf)和目錄級的(.htaccess)兩種方式。如果要想用到rewrite模組,必須先安裝或載入rewrite模組。方法有兩種一種是編譯apache的時候就直接安裝rewrite模組,別一種是編譯apache時以DSO模式安裝apache,然後再利用源碼和apxs來安裝rewrite模組。

基於伺服器級的(httpd.conf)

有兩種方法,一種是在httpd.conf的全局下直接利用RewriteEngine on來打開rewrite功能;另一種是在局部里利用RewriteEngine on來打開rewrite功能,下面將會舉例說明,需要注意的是,必須在每個virtualhost里用RewriteEngine on來打開rewrite功能。否則virtualhost里沒有RewriteEngine on它裡面的規則也不會生效。

基於目錄級的(.htaccess)

要注意一點那就是必須打開此目錄的FollowSymLinks屬性且在.htaccess里要聲明RewriteEngine on。

如何使用Rewrite 功能(Apache)

一.我們通過在IIS中安裝一個名為 ISAPI_Rewrite 的ISAPI篩選器來實現 Rewrite 功能,您需要做的事情只有一個,就是修改配置檔案 httpd.ini ,有關該組件的詳細使用方法,您可以登錄該組件官方網站 http://www.somesite.com/ 來學習,這裡我們舉一個簡單的例子來說明它的用法。

假設您要實現這樣的 Rewrite 功能:您希望當用戶訪問 /about.htm ( 您的空間裡可以並不需要存在 about.htm)的時候實際訪問的是 /index.html 。

設定方法是:

1、創建一個文本檔案,內容為

[ISAPI_Rewrite]

RewriteRule /about\.htm /index\.html

這裡,RewriteRule 這一行即為規則行,這一行由三部分組成,三部分由空格隔開,第一部分即 RewriteRule 這幾個字,第二部分為用戶訪問的地址(使用正則表達式),第三部分為實際存在於伺服器上的檔案路徑。

2、將上述檔案保存,命名為 httpd.ini 。

3、將這個檔案上傳到您的網站根目錄中,對於我們的虛擬主機,即上傳至 /web 資料夾中。

這時,當您訪問 about.htm 的時候,看到的就是 index.html 的內容。

Rewrite 是一個功能強大的平台,要真正的使用它,您可能要花費相當長的時間來學習。如果您使用像 Discuz! 論壇等支持偽靜態的系統,而僅僅是需要使用偽靜態功能,那么您可以不必學習,直接複製論壇開發者提供的配置檔案即可,但要注意配置檔案必須命名為 httpd.ini ,並且這個檔案必須放在網站的根目錄下。

httpd.ini 修改或者上傳後一般會立即生效,如果長時間不能生效,請登錄主機控制臺將網站停止然後再啟動。

評述:不建議修改http.conf檔案,因為這樣需要重新啟動apache。建議在項目的根目錄建立一個文檔,文檔名字就是.htaccess,然後把重寫規則寫進去,這樣就不需要重啟apache。

二、怎樣藉助 Rewrite 功能為特定的域名顯示特定資料夾中的內容?

這實際上是 Rewrite 功能的巧用,因為我們既然可以將 /about.htm 重寫為 /index.html ,我們也就可以把 /about.htm 重寫為 /about/ 。下面我們講具體的實現方法。

我們假設您有兩個域名 www.name1.com 和 www.name2.com ,我們實現讓訪問 www.name1.com 時看到的是網站根下的內容,而訪問 www.name2.com 時看到的是 /name2/ 資料夾中的內容。

那么設定步驟如下:

1、將您的網站捆綁域名 www.name1.com 和 www.name2.com ,這個非常重要,兩個域名都要捆綁。這時候如果不做設定,兩個域名訪問的都是網站根下。

2、修改上述問題一中的 httpd.ini 檔案,在尾部增加以下內容:

RewriteCond Host: www\.name2\.com

# 表示下一行規則只對 www.name2.com 生效(正則表達式中 \. 表示 . 本身)。

RewriteRule ^(.*)$ /name2/$1 [I]

# 表示將所有網頁 Rewrite 到 name2 資料夾中,[I]表示忽略大小寫。

請確認上述內容位於 [ISAPI_Rewrite] 行之下,如果原本網站不存在 httpd.ini 檔案,請將上述內容前面加上 [ISAPI_Rewrite] 。

3、將修改後的 httpd.ini 上傳到網站根下覆蓋原檔案。

通過這個方法,您可以將捆綁在網站上的任何一個域名採用任何特定的 Rewirte 規則,實現類似捆綁子目錄的功能當然也是不在話下。這樣,您的空間能捆綁多少個域名,您就可以建立多少個內容不同的網站了。

如何使用Rewrite 功能(nginx)

ngx_http_rewrite_module模組允許正則替換URI,返回頁面重定向,和按條件選擇配置。

ngx_http_rewrite_module模組指令按以下順序處理:

•處理在server級別中定義的模組指令;

•為請求查找location;

•處理在選中的location中定義的模組指令。如果指令改變了URI,按新的URI查找location。這個循環至多重複10次,之後nginx返回錯誤500 (Internal Server Error)。

指令

語法:break;
默認值:
上下文:server,location,if

停止處理當前這一輪的ngx_http_rewrite_module指令集。

舉例:

if ($slow) { limit_rate 10k; break;}

語法:if(condition) { ... }
默認值:
上下文:server,location

計算指定的 condition的值。如果為真,執行定義在大括弧中的rewrite模組指令,並將if指令中的配置指定給請求。if指令會從上一層配置中繼承配置。

條件可以是下列任意一種:

•變數名;如果變數值為空或者是以“0”開始的字元串,則條件為假;

•使用“=”和“!=”運算符比較變數和字元串;

•使用“~”(大小寫敏感)和“~*”(大小寫不敏感)運算符匹配變數和正則表達式。正則表達式可以包含匹配組,匹配結果後續可以使用變數$1..$9引用。如果正則表達式中包含字元“}”或者“;”,整個表達式應該被包含在單引號或雙引號的引用中。

•使用“-f”和“!-f”運算符檢查檔案是否存在;

•使用“-d”和“!-d”運算符檢查目錄是否存在;

•使用“-e”和“!-e”運算符檢查檔案、目錄或符號連結是否存在;

•使用“-x”和“!-x”運算符檢查執行檔;

舉例:

if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break;}if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1;}if ($request_method = POST) { return 405;}if ($slow) { limit_rate 10k;}if ($invalid_referer) { return 403;}

內嵌變數$invalid_referer的值是通過valid_referers指令設定的。

語法:returncode[text];
returncodeURL;
returnURL;
默認值:
上下文:server,location,if

停止處理並返回指定 code給客戶端。返回非標準的狀態碼444可以直接關閉連線而不返迴響應頭。

從0.8.42版開始,可以在指令中指定重定向的URL(狀態碼為301、302、303和307),或者指定回響體 文本(狀態碼為其它值)。回響體文本或重定向URL中可以包含變數。作為一種特殊情況,重定向URL可以簡化為當前server的本地URI,那么完整的重定向URL將按照請求協定($scheme)、server_name_in_redirect指令和port_in_redirect指令的配置進行補全。

另外,狀態碼為302的臨時重定向使用的 URL可以作為指令的唯一參數。該參數應該以“http://”、“https://”或者“https://”開始。 URL中可以包含變數。

0.7.51版本以前只能返回下面狀態碼: 204、400、402— 406、408、410、411、413、416 和 500— 504。

直到1.1.16和1.0.13版,狀態碼307才被認為是一種重定向。

語法:rewriteregexreplacement[flag];
默認值:
上下文:server,location,if

如果指定的正則表達式能匹配URI,此URI將被 replacement參數定義的字元串改寫。rewrite指令按其在配置檔案中出現的順序執行。flag可以終止後續指令的執行。如果replacement的字元串以“http://”或“https://”開頭,nginx將結束執行過程,並返回給客戶端一個重定向。

可選的 flag參數可以是其中之一:

•last

•停止執行當前這一輪的ngx_http_rewrite_module指令集,然後查找匹配改變後URI的新location;

•break

•停止執行當前這一輪的ngx_http_rewrite_module指令集;

•redirect

•在replacement字元串未以“http://”或“https://”開頭時,使用返回狀態碼為302的臨時重定向;

•permanent

•返回狀態碼為301的永久重定向。

完整的重定向URL將按照請求協定($scheme)、server_name_in_redirect指令和port_in_redirect指令的配置進行補全。

舉例:

server { ... rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last; return 403; ...}

但是當上述指令寫在“/download/”的location中時,應使用標誌break代替last,否則nginx會重複10輪循環,然後返回錯誤500:

location /download/ { rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break; return 403;}

如果 replacement字元串包括新的請求參數,以往的請求參數會添加到新參數後面。如果不希望這樣,在replacement字元串末尾加一個問號“?”,就可以避免,比如:

rewrite ^/users/(.*)$ /show?user=$1? last;

如果正則表達式中包含字元“}”或者“;”,整個表達式應該被包含在單引號或雙引號的引用中。

語法:rewrite_logon|off;
默認值:rewrite_log off;
上下文:http,server,location,if

開啟或者關閉將ngx_http_rewrite_module模組指令的處理日誌以notice級別記錄到錯誤日誌中。

語法:setvariablevalue;
默認值:
上下文:server,location,if

為指定變數 variable設定變數值 value。 value可以包含文本、變數或者它們的組合。

語法:uninitialized_variable_warnon|off;
默認值:uninitialized_variable_warn on;
上下文:http,server,location,if

控制是否記錄變數未初始化的警告到日誌。

內部實現

ngx_http_rewrite_module模組的指令在解析配置階段被編譯成nginx內部指令。這些內部指令在處理請求時被解釋執行。而解釋器是一個簡單的堆疊機器。

比如,下面指令

location /download/ { if ($forbidden) { return 403; } if ($slow) { limit_rate 10k; } rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;}

將被翻譯成下面這些指令:

variable $forbiddencheck against zero return 403 end of codevariable $slowcheck against zeromatch of regular expressioncopy "/"copy $1copy "/mp3/"copy $2copy ".mp3"end of regular expressionend of code

請注意沒有對應上面的limit_rate指令的內部指令,因為這個指令與ngx_http_rewrite_module模組無關。nginx會為這個if塊單獨創建一個配置,包含limit_rate等於10k。如果條件為真,nginx將把這個配置指派給請求。

指令

rewrite ^/(download/.*)/media/(.*)\..*$ /$1/mp3/$2.mp3 break;

可以通過將正則表達式中的第一個斜線“/”放入圓括弧,來實現節約一個內部指令:

rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;

對應的內部指令將會是這樣:

match of regular expressioncopy $1copy "/mp3/"copy $2copy ".mp3"end of regular expressionend of code

相關詞條

熱門詞條

聯絡我們