Apache URL重寫規則

一、簡介

  Apached的重寫功能,便是mod_rewrite模塊功能,它是apache的一個模塊。它的功能很是強大,能夠操做URL中的全部部分。php

  所以咱們就能夠改寫url,給用戶提供一個簡介大方的url,當用戶訪問時能夠經過mod_rewrite模塊功能轉換爲真正的資源路徑。經過mod_rewrite能實現的功能還有不少,例如隱藏真實地址、實現URL跳轉、域名跳轉、防盜鏈、限制訪問資源類型等等。html

二、工做流程

  mod_rewrite模塊在運行時會使用兩個Hook程序。正則表達式

  第一個是從URL到文件名轉換的Hook。當有訪問到達Apache服務器的時,服務器會確認相應主機(或虛擬主機),這時mod_rewrite模塊就開始工做,它將會先處理服務器全局中mod_rewrite模塊所提供的指令,而後根據用戶提供的指令進行改寫。apache

  第二個是修正URL的Hook。在此階段mod_rewrite模塊會處理非全局的設置。例如,目錄中的.htaccess文件中的設置。可是此時已經完成URL的翻譯(由URL轉換爲文件名),所以是沒法在次對目錄級別的URL進行改寫操做,可是moe_rewrite模塊會將已翻譯的URL再次轉換爲URL的狀態,繼續進行目錄級別的URL改寫。(mod_rewrite模塊將會使用讀後請求階段的回叫函數從新開始一個請求的循環處理)api

Rewirte模塊規則集的處理瀏覽器

  當mod_rewrite在這兩個API階段中開始執行時,它會讀取配置結構中配置好的 (或者是在服務啓動時創建的服務器級的,或者是在遍歷目錄採集到的目錄級的)規則集,而後,啓動URL重寫引擎來處理(帶有一個或多個條件的)規則集。不管是服務器級的仍是目錄級的規則集,都是由同一個URL重寫引擎處理,只是最終結果處理不一樣而已。安全

  規則集中規則的順序是很重要的,由於重寫引擎是按一種特殊的順序處理的:逐個遍歷每一個規則(RewriteRule指令),若是出現一個匹配條件的規則,則可能回頭遍歷已有的規則條件(RewriteCond指令)。因爲歷史的緣由,條件規則是前置的,因此控制流程略顯冗長,細節見圖-1。服務器

  可見,URL首先與每一個規則的Pattern匹配,若是匹配失敗,mod_rewrite將當即終止此規則的處理,繼而處理下一個規則。若是匹配成功,mod_rewrite將尋找相應的規則條件,若是一個條件都沒有,則簡單地用Substitution構造的新值來替換URL,而後繼續處理其餘規則;可是若是條件存在,則開始一個內部循環按其列出的順序逐個處理。對規則條件的處理有所不一樣:URL並不與模式進行匹配,而是首先經過擴展變量、反向引用、查找映射表等步驟創建一個TestString字符串,而後用它來與CondPattern匹配。若是匹配失敗,則整個條件集和對應的規則失敗;若是匹配成功,則執行下一個規則直到全部條件執行完畢。若是全部條件得以匹配,則以Substitution替換URL,而且繼續處理。(本部分引用譯者:金步國)cookie

網絡圖片:網絡

 

三、URL重寫指令

  最簡單的重寫指令能夠簡單到讓你沒法想象!

  只須要兩步就能夠完成了。第一使用RewriteEngine開啓mod_rewrite模塊功能;第二經過RewriteRule定義URL重寫規則

  1)、URL重寫指令套路

1 ---------------------------------------------------------------
2 RewriteEngine on   #開啓mod_rewrite模塊功能
3 RewriteBase 路徑     #基準URL(使用alias設置別名則需使用這個)
4 RewriteCond TestString CondPattern [flags]      #重寫條件(能夠多個)
5 RewriteRule Pattern Substitution [flags]          #重寫規則
6 ----------------------------------------------------------------
7 #四、5行能夠能夠多個
8 #按順序一個一個執行RewriteRule([flags不終止狀況下])
9 ##以上是經常使用的指令,還有一些不多見的指令,須要的本身去查資料瞭解

  2)、RewriteRule Pattern Substitution [flags]

  一、pattern是做用於當前URL的perl兼容的正則表達式。當前URL是指該規則生效時刻的URL的值。它可能與被請求時的URL大相徑庭,由於以前可能被其餘RewriteRule或者alias指令修改過。

  二、Substitution是當URL與Pattern匹配成功後。用來代替的字符串。

  • 能夠對pattern反向引用$N(N=0~9),表示正則表達式中第N個括號中的內容
  • 對最後匹配的RewriteCond反向引用%N(N=0~9),表示最後匹配的RewriteCond第N對括號中的內容
  • 服務器變量%{VARNAME}
  • 映射函數調用${mapname:key|default} (經過RewriteMap指令定義映射輔助完成)

  三、[flags],標誌符,多個則用逗號隔開。

標誌符(摘抄於網上):

redirect|R [=code] (強制重定向 redirect)

  以 http://thishost[:thisport]/(使新的URL成爲一個URI) 爲前綴的Substitution能夠強制性執行一個外部重定向。 若是code沒有指定,則產生一個HTTP響應代碼302(臨時性移動)。若是須要使用在300-400範圍內的其餘響應代碼,只需在此指定這個數值便可, 另外,還可使用下列符號名稱之一: temp (默認的), permanent, seeother. 用它能夠把規範化的URL反饋給客戶端,如, 重寫「/~」爲 「/u/」,或對/u/user加上斜槓,等等。

注意: 在使用這個標記時,必須確保該替換字段是一個有效的URL! 不然,它會指向一個無效的位置! 而且要記住,此標記自己只是對URL加上 http://thishost[:thisport]/的前綴,重寫操做仍然會繼續。一般,你會但願中止重寫操做而當即重定向,則還須要使用’L’標記.

forbidden|F (強制URL爲被禁止的 forbidden)

  強制當前URL爲被禁止的,即,當即反饋一個HTTP響應代碼403(被禁止的)。使用這個標記,能夠連接若干RewriteConds以有條件地阻塞某些URL。

gone|G(強制URL爲已廢棄的 gone)

  強制當前URL爲已廢棄的,即,當即反饋一個HTTP響應代碼410(已廢棄的)。使用這個標記,能夠標明頁面已經被廢棄而不存在了.

proxy|P (強制爲代理 proxy)

  此標記使替換成分被內部地強制爲代理請求,並當即(即, 重寫規則處理當即中斷)把處理移交給代理模塊。你必須確保此替換串是一個有效的(好比常見的以 http://hostname開頭的)可以爲Apache代理模塊所處理的URI。使用這個標記,能夠把某些遠程成分映射到本地服務器名稱空間, 從而加強了ProxyPass指令的功能。

注意: 要使用這個功能,代理模塊必須編譯在Apache服務器中。 若是你不能肯定,能夠檢查「httpd -l」的輸出中是否有mod_proxy.c。 若是有,則mod_rewrite可使用這個功能;若是沒有,則必須啓用mod_proxy並從新編譯「httpd」程序。

last|L (最後一個規則 last)

  當即中止重寫操做,並再也不應用其餘重寫規則。 它對應於Perl中的last命令或C語言中的break命令。這個標記能夠阻止當前已被重寫的URL爲其後繼的規則所重寫。 舉例,使用它能夠重寫根路徑的URL(’/’)爲實際存在的URL, 好比, ‘/e/www/’.

next|N (從新執行 next round)

  從新執行重寫操做(從第一個規則從新開始). 這時再次進行處理的URL已經不是原始的URL了,而是經最後一個重寫規則處理的URL。它對應於Perl中的next命令或C語言中的continue命令。 此標記能夠從新開始重寫操做,即, 當即回到循環的頭部。
可是要當心,不要製造死循環!

chain|C (與下一個規則相連接 chained)

  此標記使當前規則與下一個(其自己又能夠與其後繼規則相連接的, 並能夠如此反覆的)規則相連接。 它產生這樣一個效果: 若是一個規則被匹配,一般會繼續處理其後繼規則, 即,這個標記不起做用;若是規則不能被匹配,則其後繼的連接的規則會被忽略。好比,在執行一個外部重定向時, 對一個目錄級規則集,你可能須要刪除「.www」 (此處不該該出現「.www」的)。

type|T=MIME-type(強制MIME類型 type)

  強制目標文件的MIME類型爲MIME-type。 好比,它能夠用於模擬mod_alias中的ScriptAlias指令,之內部地強制被映射目錄中的全部文件的MIME類型爲「application/x-httpd-cgi」。

nosubreq|NS (僅用於不對內部子請求進行處理 no internal sub-request)

  在當前請求是一個內部子請求時,此標記強制重寫引擎跳過該重寫規則。好比,在mod_include試圖搜索可能的目錄默認文件(index.xxx)時, Apache會內部地產生子請求。對子請求,它不必定有用的,並且若是整個規則集都起做用,它甚至可能會引起錯誤。因此,能夠用這個標記來排除某些規則。

  根據你的須要遵循如下原則: 若是你使用了有CGI腳本的URL前綴,以強制它們由CGI腳本處理,而對子請求處理的出錯率(或者開銷)很高,在這種狀況下,可使用這個標記。

nocase|NC (忽略大小寫 no case)

  它使Pattern忽略大小寫,即, 在Pattern與當前URL匹配時,’A-Z’ 和’a-z’沒有區別。

qsappend|QSA (追加請求串 query string append)

  此標記強制重寫引擎在已有的替換串中追加一個請求串,而不是簡單的替換。若是須要經過重寫規則在請求串中增長信息,就可使用這個標記。

noescape|NE (在輸出中不對URI做轉義 no URI escaping)

  此標記阻止mod_rewrite對重寫結果應用常規的URI轉義規則。 通常狀況下,特殊字符(如’%’, ‘$’, ‘;’等)會被轉義爲等值的十六進制編碼。 此標記能夠阻止這樣的轉義,以容許百分號等符號出如今輸出中,如:

  RewriteRule /foo/(.*) /bar?arg=P1=$1 [R,NE] 可使’/foo/zed’轉向到一個安全的請求’/bar?arg=P1=zed’.

passthrough|PT (移交給下一個處理器 pass through)

  此標記強制重寫引擎將內部結構request_rec中的uri字段設置爲 filename字段的值,它只是一個小修改,使之能對來自其餘URI到文件名翻譯器的 Alias,ScriptAlias, Redirect 等指令的輸出進行後續處理。舉一個能說明其含義的例子:若是要經過mod_rewrite的重寫引擎重寫/abc爲/def,而後經過mod_alias使/def轉變爲/ghi,能夠這樣:

RewriteRule ^/abc(.*) /def$1 [PT]

Alias /def /ghi
  若是省略了PT標記,雖然mod_rewrite運做正常, 即, 做爲一個使用API的URI到文件名翻譯器,它能夠重寫uri=/abc/…爲filename=/def/…,可是,後續的mod_alias在試圖做URI到文件名的翻譯時,則會失效。

注意: 若是須要混合使用不一樣的包含URI到文件名翻譯器的模塊時, 就必須使用這個標記。。混合使用mod_alias和mod_rewrite就是個典型的例子。

For Apache hackers

  若是當前Apache API除了URI到文件名hook以外,還有一個文件名到文件名的hook, 就不須要這個標記了! 可是,若是沒有這樣一個hook,則此標記是惟一的解決方案。 Apache Group討論過這個問題,並在Apache 2.0 版本中會增長這樣一個hook。

skip|S=num (跳事後繼的規則 skip)

  此標記強制重寫引擎跳過當前匹配規則後繼的num個規則。 它能夠實現一個僞if-then-else的構造: 最後一個規則是then從句,而被跳過的skip=N個規則是else從句. (它和’chain|C’標記是不一樣的!)

env|E=VAR:VAL (設置環境變量 environment variable)

  此標記使環境變量VAR的值爲VAL, VAL能夠包含可擴展的反向引用的正則表達式$N和%N。 此標記能夠屢次使用以設置多個變量。這些變量能夠在其後許多狀況下被間接引用,但一般是在XSSI (via ) or CGI (如 $ENV{’VAR’})中, 也能夠在後繼的RewriteCond指令的pattern中經過%{ENV:VAR}做引用。使用它能夠從URL中剝離並記住一些信息。

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

  它在客戶端瀏覽器上設置一個cookie。 cookie的名稱是NAME,其值是VAL。 domain字段是該cookie的域,好比’.apache.org’, 可選的lifetime是cookie生命期的分鐘數,可選的path是cookie的路徑。

  3)、RewriteCond TestString CondPattern [flags]

  Rewritecond指令定義一條規則條件。在一條rewriterule指令前面可能會有一條或者多條rewritecond指令,只有當自身模板匹配成功且這些條件也知足時(即RewriteRule中的pattern匹配成功),規則條件才被應用於當前URL處理。

  一、TestString是一個純文本的字符串

  • 能夠對pattern反向引用$N(N=0~9),緊跟在RewriteCond後面的RewriteRule正則表達式中第N個括號中的內容
  • 反向引用%N(N=0~9),表示RewriteCond中CondPattern中第N對括號中的內容
  • 服務器變量%{VARNAME}

  二、CondPattern是條件pattern,一個應用於當前實例TestString的正則表達式。即TestString與條件pattern條件進行匹配。若是匹配則RewriteCond的值爲Rrue,反之爲False

可使用如下特殊變量(可以使用'!'實現反轉):

'>CondPattern’ (大於) 將condPattern看成一個普通字符串,將它和TestString進行比較,當TestString 的字符大於CondPattern爲真。

‘=CondPattern’ (等於) 將condPattern看成一個普通字符串,將它和TestString進行比較,當TestString 與CondPattern徹底相同時爲真.若是CondPattern只是 「」 (兩個引號緊挨在一塊兒) 此時需TestString 爲空字符串方爲真。

‘-d’ (是否爲目錄) 將testString看成一個目錄名,檢查它是否存在以及是不是一個目錄。

‘-f’ (是不是regular file) 將testString看成一個文件名,檢查它是否存在以及是不是一個regular文件。

‘-s’ (是否爲長度不爲0的regular文件) 將testString看成一個文件名,檢查它是否存在以及是不是一個長度大於0的regular文件。

‘-l’ (是否爲symbolic link) 將testString看成一個文件名,檢查它是否存在以及是不是一個 symbolic link。

‘-F’ (經過subrequest來檢查某文件是否可訪問) 檢查TestString是不是一個合法的文件,並且經過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是經過一個內部subrequest完成的, 所以須要當心使用這個功能以下降服務器的性能。

‘-U’ (經過subrequest來檢查某個URL是否存在) 檢查TestString是不是一個合法的URL,並且經過服務器範圍內的當前設置的訪問控制進行訪問。這個檢查是經過一個內部subrequest完成的, 所以須要當心使用這個功能以下降服務器的性能。

   三、[flags]是第三個參數,多個標誌之間用逗號隔開

’nocase|NC’ (不區分大小寫)   在擴展後的TestString和CondPattern中,比較時不區分文本的大小寫。注意,這個標誌對文件系統和subrequest檢查沒有影響.

’ornext|OR’ (創建與下一個條件的或的關係)   默認的狀況下,二個條件之間是AND的關係,用這個標誌將關係改成OR。

 

  4)、Rewrite時服務器變量(僅列出少數)

HTTP headers:HTTP_USER_AGENT,  HTTP_REFERER,  HTTP_COOKIE,  HTTP_HOST,  HTTP_ACCEPT

connection & request:REMOTE_ADDR,  QUERY_STRING

server internals::DOCUMENT_ROOT,  SERVER_PORT,  SERVER_PROTOCOL

system stuff: TIME_YEAR,  TIME_MON,  TIME_DAY

 

  5)、簡單正則表達式規則

. 匹配任何單字符

[chars] 匹配字符串:chars

[^chars] 不匹配字符串:chars

text1|text2 可選擇的字符串:text1或text2

? 匹配0到1個字符

* 匹配0到多個字符

+ 匹配1到多個字符

^ 字符串開始標誌

$ 字符串結束標誌

\n 轉義符標誌

 【注意】:一代Apache要求URL有斜槓而二代Apache卻不容許,所以使用 ^/?

 

四、例子解析

例1(簡單例子):

(在.htaccess裏進行規制重寫)

RewriteEngine ON 
RewriteRule  ^user/(w+)/?$user.php?id=$1

^:輸入的開頭  以user/開頭請求的地址

(w+):提取全部的字母,傳給$1

/?:可選斜槓

$:結束符

替換爲:user.php?id=*

注意:有些apache(具體哪一個版本忘啦)不兼容簡寫模式 w+ => [a-zA-Z_-]

 例2(禁止IE和Opera瀏覽器訪問):

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* - [F,L]       #'-'表示不替換URL

例3(不合法路徑返回首頁):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

例4(防盜鏈):

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?mysite.com/ [NC]       #判斷請求的是不是本身的域名
RewriteCond %{HTTP_REFERER} !^$                     #{HTTP_REFERER}不爲空
RewriteRule .*.(jpe?g|gif|bmp|png)$ /images/nohotlink.jpg [L]      #返回警告圖片

例5(改變訪問URL目錄名):

即隱藏真實的目錄名字

RewriteEngine On
RewriteRule ^/?old_dir/([a-z\.]+)$  new_dir/$1 [R=301,L]
#new_dir爲真正目錄

例6(建立無文件後綴連接):

RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f #判斷該後綴文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f #判斷該後綴文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]

例7(限制只能顯示圖片):

RewriteEngine on
RewriteCond %{REQUEST_FILENAME}  !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ - [F,L]

例8(文件不存在重定向404):

RewriteEngine on
RewriteCond  %{REQUEST_FILENAME}  !f
RewriteCond  %{REQUEST_FILENAME}  !d
RewriteRule .? /404.php [L]

 

 (以上是本身的一些看法與總結,如有不足或者錯誤的地方請各位指出)

做者:那一葉隨風

聲明:以上只表明本人在工做學習中某一時間內總結的觀點或結論。轉載時請在文章頁面明顯位置給出原文連接

相關文章
相關標籤/搜索