話說這篇文章似乎受眾非常小,所以如果不知道這標題是什麼意思的話……可以不用看了,哈哈哈。
Apache 有一個重要的功能就是 URL 與檔案可以完全無關,可以透過 Rewrite 規則來改變實際的 URL。
而且這個功能其實非常有用,最常見的幾個應用:
- 更換域名了或檔案轉移了,讓舊位址也能存取到相應的檔案。
- 防止盜鏈,只允許特定網站引用檔案
- 偽靜態,隱藏 .php 檔名,將其變成 .html 或直接是路徑的形式
- 自訂 404 等錯誤頁面
最近因為在折騰自己的兩個網站,於是除了防盜鏈這功能沒用到以外,剩下的都實踐了一遍……
不得不說這玩意真是一個很反人類的東西,尤其是在你不太會的時候,發現複製別人的代碼也看不懂,不知道怎麼改……
想增加自己的需求那更是無限茫然,於是果然花了半天時間學習了一下……
好的,下面我來簡單介紹一下這玩意……
先說說什麼是 .htaccess:
.htaccess 檔案(或者「分散式設定檔」)提供了針對目錄改變設定的方法,即,在一個特定的文件目錄中放置一個包含一個或多個指令的檔案,以作用於此目錄及其所有子目錄。作為使用者,所能使用的命令受到限制。管理員可以透過 Apache 的 AllowOverride 指令來設定。
概述來說,htaccess 檔案是 Apache 伺服器中的一個設定檔,它負責相關目錄下的網頁設定。透過 htaccess 檔案,可以幫我們實現:網頁 301 重新導向、自訂 404 錯誤頁面、改變副檔名、允許/阻止特定的使用者或者目錄的存取、禁止目錄列表、設定預設文件等功能。
啟用 .htaccess,需要修改 httpd.conf,啟用 AllowOverride,並可以用 AllowOverride 限制特定命令的使用。如果需要使用 .htaccess 以外的其他檔名,可以用 AccessFileName 指令來改變。例如,需要使用 .config ,則可以在伺服器設定檔中按以下方法設定:AccessFileName .config。
當然,其實這些設定是可以直接寫在 httpd.conf 或 vhosts 裡的虛擬主機設定檔中的,
但是 .htaccess 具有更方便控制修改,不用重啟服務等優點。
它的控制範圍為它所在的資料夾及其子資料夾,所以可以在子資料夾下使用來進行更小範圍的控制。
缺點也是很明顯的,就是效能的考慮,如果 AllowOverride 啟用了 .htaccess 檔案,
每存取一次 Apache 需要在當前目錄及所有父級目錄中尋找 .htaccess 檔案,
即使不存在 .htaccess 檔案,因此,無論是否真正用到,啟用 .htaccess 都會導致效能的下降。
當然像我這種小站其實完全不用考慮這些效能上的因素啦,於是果斷的開始實踐~~~~
通常這個檔案是在某域名的根目錄下的,如果不存在則新建一個,如果存在則直接修改。
但是修改前建議您先能看明白原來的……以免發生衝突。
先來說說它的基本語法:
<IfModule mod_rewrite.c> RewriteEngine On 语句。。。。 </IfModule>
這裡 RewriteEngine On 和 Off 可以輕鬆控制以下所有語句是否有效,
在除錯的時候還有用,另外單獨一句話可以透過在前面加 # 來註解掉。
Okay,下面說說常用的語句:
通常每一個重新導向都是這樣的:
先由一個或多個 RewriteCond 做為條件,滿足條件的,
由 RewriteRule 來進行跳轉。
比較常見的變數有 HTTP_HOST:域名,REQUEST_URI:域名後面那部分,REQUEST_FILENAME:檔名。
最後還有個參數,常用的有[NC]:不區分大小寫,[R]:重新導向,[L]:不繼續執行。
條件則是使用了正規表達式,對於熟悉正規表達式的人來說,那真是變容易了,
對於不熟悉的人來說真是一頭霧水,具體可以在這裡補充相關知識:http://zh.wikipedia.org/zh/正则表达式
主要要注意的是開始和結束的標誌,比如說如果是空的話就是 ^$。
更多變數參數及其代表的意義可以參考這裡:http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html
下面舉幾個例子來說明,比如說要把所有存取 domain.com 的都轉向 www.domain.com,
當然反之也是可以的,或者用於替換域名也是可以的。
這裡條件是 HTTP_HOST 滿足 domain.com,規則是轉向 www.domain.com,後面的內容保留。
不區分大小寫,永久重新導向。
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [R=301,L]
同樣像我在上一篇 BLOG 中提到的,把 /wp-content/uploads/ 的請求重新導向到 cdn.cnsjw.cn/uploads/ 下:
RewriteCond %{REQUEST_URI} ^/wp-content/uploads/
RewriteRule /wp-content/uploads/(.*) https://img.cnsjw.cn/$1 [R=301,L]
這裡重新導向就意味著告訴瀏覽器和搜尋引擎,這個位址永遠的變了,
所以重新導向後會直接跳轉到新的位址去。
還有就是錯誤頁面的自訂,語法非常簡單:
ErrorDocument 404 /404.html
這樣就可以實現 404 錯誤的自訂頁面了。
而 Rewrite 最常用的情況不是重新導向,而是偽靜態,
舉的例子是 eitdesign.com,這個網站之前的頁面邏輯就是
eitdesign.com/home, eitdesign.com/about,等等,當時並非偽靜態,而是真靜態……
實現的方法是建立 home, about 等等資料夾,並在裡面直接使用 index 檔案輸出當前頁。
當時全站的檔案結構如下:

這個方法的問題很多,比如說每個頁面都要寫一次,只有這種簡單的小網站才能實現。
修改起來很麻煩,而且所有的頁面檔名都是 index,所以開多了很混亂……
因為還有英文版,但是實在沒有辦法再新建一個 /en 資料夾再寫一遍這些檔案了……
於是就用了 ?lan=en 來控制語言版本,當時是沒有這個參數就是中文版,有就是英文版。
這樣就導致了檔名不統一,也明顯不夠友好。
現在採取的方法是除了 service 頁面以外,其它所有頁面全部由 index.php 來處理,
內容部分從 xml 中讀取,代碼只實現功能部分。現在的檔案結構是這樣的:

於是把所有的 services 請求做另外的 rewrite,剩下的部分都直接 rewrite 到 index.php?p= 裡。
這樣只要在 index.php 裡判斷傳過來的 p 參數就可以了,比如說存取 http://www.eitdesign.com/home/en
實際上是在存取 http://www.eitdesign.com/index.php?p=home/en
然後由 PHP 來處理這個參數就容易得多了,用 explode 按照 / 來打散,判斷 / 前面的部分和後面的部分,
就可以輕鬆的得知要存取哪個頁面,哪種語言版本。
另外,要先判斷不是檔名或資料夾名的話,則進行 Rewrite……否則會導致正常的檔案無法存取。
RewriteCond %{REQUEST_URI} services/en/
RewriteRule . /services/en.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} services/
RewriteRule . /services/cn.html [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?p=$1
這樣就實現了偽靜態……
還有一個需求就是讓存取 www.eitdesign.com 重新導向到 www.eitdesign.com/home/
RewriteRule ^$ /home/ [R=301,L]
這裡要注意就是如果是在 vhosts 裡設定的話,存取 www.eitdesign.com 的時候,
REQUEST_URI 是 / 而不是空,只有在 .htaccess 中設定的時候才是空的。
總結下來其實自己也是初學者,但是呢,還是可以寫得出來一些規則的……
主要要注意的有以下幾點:
- 判斷的時候設定好條件的起始和結束標記,否則就變成了包含關係。
- 避免重複轉移,以及進入死循環等問題。
- 還有語句的順序,滿足某個條件的話就可以在結尾加[L]不再繼續。
- 注意二級域名,如果是某個目錄的子目錄的話,上級目錄的 .htaccess 同樣會適用於二級域名的,可能會產生錯誤,可以在二級域名目錄的 .htaccess 下禁止轉移。
其實自己設定伺服器還挺有趣的,記得常常關注各種 error log,
可以不斷的改進自己的代碼以及伺服器的設定。

