Apache 和 Nginx 下的 URL 重寫

 

 

URL 重寫和重定向

URL 重寫是將頁面映射到本站另外一頁面, 而重定向則是將頁面映射到另外一主機(域名). 其中臨時重定向(R=302)和永久重定向(R=301)都是親搜索引擎的, 是 SEO 的重要技術. 經過重定向, 瀏覽器和搜索引擎都意思到頁面發生了變化, 從而分別改變地址欄顯示的地址和更新搜索引擎索引。php

 

Apache 中的 URL 重寫和重定向

啓用Apache 的 URL 重寫功能, 須要開啓mod_rewrite模塊.。而後在服務器配置文件或htaccess中修改服務配置:
AllowOverride all
Options FollowSysLinks
服務器配置文件和htaccess文件中均可以配置 URL 重寫,前者是服務器級別, 後者是目錄級別。
 

開啓重寫日誌

2.4 如下版本html

在Apache 服務器配置文件中追加:
RewriteLog "自定義日誌路徑"
# 設置日誌等級
RewriteLogLevel 9
等級0 爲關閉, 9 表示輸出最詳細信息。
 

2.4 及其以上版本web

在Apache 服務器配置文件中追加:正則表達式

LogLevel alert rewrite:trace3
其中trace3 能夠替換爲 trace1 到 trace8, 數值越大輸出的信息越詳細. 最後輸出的日誌信息在apache_error.log文件中.
注意: 日誌級別越高, 越影響服務器性能. 生產環境下應關閉重寫日誌.
 

重寫指令

RewriteEngineapache

RewriteEngine: 是否啓用重寫引擎. On啓用, Off不啓用.

RewriteBaseapi

RewriteBase: 設置重寫的基準目錄. 基準目錄的根目錄就是網站的根目錄.

RewriteCond瀏覽器

RewriteCond: 設置重寫條件.
語法: 
RewriteCond TestString CondPattern [flags]

RewriteCond 指令定義一條規則條件。安全

在一條 RewriteRule 指令前面可能會有一條或多條 RewriteCond 指令,只有 TestString 符合 CondPattern 時規則才被應用於當前URL處理。服務器

1) TestString是一個純文本的字符串,除了包含普通的字符外,還能夠包括下列的可擴展結構:cookie

$N: RewriteRule 後向引用,其中(0 <= N <= 9) . $N引用緊跟在 RewriteCond 後面的 RewriteRule 中模板中的括號中的模板在當前 URL 中匹配的數據。

%N: RewriteCond 後向引用, 其中(0 <= N <= 9). %N引用最後一個 RewriteCond 的模板中的括號中的模板在當前 URL 中匹配的數據。

${mapname:key|default}:RewriteMap 擴展。

2) CondPattern是條件 pattern, 即一個應用於當前實例TestString 的正則表達式, 即 TestString 將會被計算而後與CondPattern 匹配. 做爲一個標準的擴展正則式, CondPattern 有如下補充:

能夠在模板串前增長一個!前綴,以表示不匹配模板。但並非全部的 test 均可以加!前綴。

CondPattern中可使用如下特殊變量:

>CondPattern: 大於, 將 CondPattern 看成一個普通字符串, 將它和 TestString 進行比較, 當T estString 的字符大於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 完成的, 所以須要當心使用這個功能以下降服務器的性能.

3) [flags]是第三個參數,多個標誌之間用逗號分隔。

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

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

RewriteCond %{REMOTE_HOST} ^host1.* [OR] RewriteCond %{REMOTE_HOST} ^host2.* [OR] RewriteCond %{REMOTE_HOST} ^host3.* RewriteRule …

若是沒有[OR]標誌,須要寫三個條件/規則。

 

RewriteRule

RewriteRule: 設置重寫規則.

語法
RewriteRule Pattern Substitution [flags].

1) Pattern是一個做用於當前 URL 的兼容 perl 的正則表達式. 這裏的「當前」是指該規則生效時的 URL 的值。

2) Substitution是當原始 URL 與 Pattern 相匹配時, 用以替代(或替換)的字符串. (RewriteRule 中也會進行一次判斷, 被捕獲的 URL 是否與 Pattern相匹配)

3) Substitution還能夠追加特殊標記[flags]做爲 RewriteRule 指令的第三個參數。 Flags 是一個包含以逗號分隔的下列標記的列表:

1.redirect|R[=code] (強制重定向 redirect)
強制性執行一個外部重定向. 若是code沒有指定, 則默認302. 若是須要使用在 300-400 範圍內的其餘響應代碼, 只需在此指定這個數值便可。

另外, 還可使用下列符號名稱之一: temp(默認的), permanent, seeother.

注意: 在使用這個標記時,務必確保該替換字段是一個有效的 URL ! 而且要記住,若是但願中止重寫操做而當即重定向,則還須要使用L標記。

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

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

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

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

4.proxy|P(強制爲代理 proxy )

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

注意: 要使用這個功能, 代理模塊必須編譯在Apache服務器中. 不能肯定, 能夠檢查httpd -l的輸出中是否有mod_proxy.c. 若是有, 則mod_rewrite可使用這個功能; 若是沒有, 則必須啓用mod_proxy並從新編譯httpd程序.
 
5.last|L(最後一個規則 last)
當即中止重寫操做, 並再也不應用其餘重寫規則. 它對應於 Perl中 的last命令或C語言中的break命令. 這個標記能夠阻止當前已被重寫的 URL 爲其後繼的規則所重寫
6.next|N(從新執行 next round)
從新執行重寫操做(從第一個規則從新開始). 這時再次進行處理的URL已經不是原始的URL, 而是經最後一個重寫規則處理的URL. 它對應於 Perl 中的next命令或C語言中的continue命令. 此標記能夠從新開始重寫操做, 即當即回到循環的頭部.

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

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

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

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

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

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

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

它使Pattern 忽略大小寫。

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

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

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

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

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

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

讓mod_rewrite 模塊將重寫的 URL 傳回給 Apache 作進一步處理。

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

若是知足某指定的條件,則跳事後面第num 調規則。

15.env|E=variable:value(設置環境變量 environment variable)

此標記使環境變量variable 的值爲 value, VAL能夠包含可擴展的反向引用的正則表達式$N和%N. 此標記能夠屢次使用以設置多個變量。這些變量能夠在後繼的 RewriteCond 指令的pattern 中經過%{ENV:VAR}做引用 。

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

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

attachments-2020-04-5a3z3CG05e8e82e678784.jpg

 

在.htaccess 文件中配置重寫規則

在.htaccess文件中使用重寫功能時, RewriteRule 負責匹配的 URI 是相對.htaccess所在的目錄而言的。
例如訪問http://example.com/subdir1/subdir2/subdir3:
  • 若是.htaccess在網站根目錄下, 那麼RewriteRule捕獲的 URI 是subdir1/subdir2/subdir3.
  • 若是.htaccess在 subdir1 目錄下, RewriteRule捕獲的 URI 是subdir2/subdir3.

RewriteRule重寫 URI 後的基準目錄也是以.htaccess所在的目錄爲準. 例如: 訪問 http://example.com/foo

RewriteRule ^foo$ bar.php [L]
若是.htaccess在根目錄下, 重寫後訪問 http://example.com/bar.php. 若是在 subdir1 目錄下, 重寫後訪問 http://example.com/subdir1/bar.php.
 

例1:

<IfModule mod_rewrite.c># 啓用rewrite引擎RewriteEngine On# 重寫規則: 匹配任意以htm後綴的文件, 將htm替換成php. ^(.*)\.htm$ 是一個正則表達式, 表示須要重寫的部分, 此處指以任意字符開頭, 以.htm結尾的部分. $1.php 是一個重寫規則, $1 表示匹配到正則表達式中第一個子模式的字符串. [NC]: 表示重寫規則如何應用, 該處表示不區分大小寫. 整條規則即重寫以任意字符開頭, 以.htm結尾的部分, 重寫爲由匹配到的第一個子模式字符串和.php拼接成的字符串。RewriteRule ^(.*)\.htm$ $1.php [NC]</IfModule>

IfModule 命令用於判斷是否安裝了 mod_rewrite 模塊。

例2:
<IfModule mod_rewrite.c>RewriteEngine On# 設置目錄級重寫的基準URIRewriteBase /subdir1/RewriteRule ^(.*)\.htm$ $1.php [NC,L,R]</IfModule>
  • RewriteBase設置了重寫的基準目錄. 若是上例中.htaccess位於網站根目錄下, 訪問的 http://example.com/foo.htm, 本來重寫後的基準目錄是網站根目錄/, 設置了RewriteBase後變爲/subdir1/, 重寫後實際訪問 http://example.com/subdir1/foo.php.
  • 規則標誌L: 表示若是能夠匹配本條規則, 則再也不繼續往下匹配.
  • 規則標誌R: 表示臨時重定向, 即 302, 至關於[R=302]。

 

例3:
<IfModule mod_rewrite.c><IfModule mod_rewrite.c>RewriteEngine OnRewriteCond %{HTTP_HOST} (localhost:81)RewriteRule ^(.*) http://localhost:82 [R=301]</IfModule>
  • [R=301]: 表示永久性重定向, 用戶發送的全部請求都會被髮送到新域名處理,永久重定向到另外一個域名使用了絕對 URI, 所以不用再設置 RewriteBase。
  • %{HTTP_HOST}:表示引用 Apache 服務器變量 HTTP_HOST。
  • 該條RewriteCond 表示判斷 HTTP_HOST 是不是 localhost:81。
 

在httpd.conf 中配置重寫規則

在服務器配置文件中配置URL 重寫的指令與 .htaccess 文件中的格式相同,須要寫在<Directory>內.

 

Nginx

Nginx 的 URL 重寫功能不須要額外的支持. Nginx 自己只支持在服務器配置文件中配置 URL 重寫規則, 不支持 .htaccess 文件. 但能夠經過在服務器配置文件中引入外部文件的方式, 實現對 .htaccess 文件的支持. 這會嚴重影響 Nginx 的性能。

 

重寫指令

rewrite

根據重寫規則, 重寫 URL。
語法:
rewrite regex replacement flag
應用環境: server, location, if
可應用的flag 標記包括:
  • last: 至關於 Apache 中的L標記。
  • break: 終止匹配, 再也不匹配後面的規則。
  • redirect: 臨時重定向, 返回 302。
  • permanent: 永久性重定向, 返回 301。
示例:
rewrite ^(.*)\.html$ $1.php last;
注意: 若是訪問的是 http://localhost/dir/file, rewrite 中的正則表達式匹配的是 /dir/file, 包括最左邊的正斜槓.

 

if 指令

語法: 
if (condition){...}
注意if以後緊跟的空格不能省略。
應用環境: server, location
判斷一個條件是否符合, 若是符合, 則執行大括號內語句. if 指令不支持嵌套, 不支持&&和||操做。

condition中能夠包含以下判斷表示:

  • ~: 區分大小寫進行匹配
  • ~*: 不區分大小寫進行匹配
  • !~: 區分大小寫進行非匹配
  • !~*: 不區分大小寫進行非匹配
  • -f: 若是文件存在
  • !-f: 若是文件不存在
  • -d: 若是目錄存在
  • !-d: 若是目錄不存在
  • -e: 若是文件或目錄存
  • !-e: 若是文件或目錄不存在
  • -x: 若是文件可執行
  • !-x: 若是文件不可執行
示例:
location ~ \.html$ {if (!-f $request_filename){rewrite (.*)\.html$ $1.php last;}}
訪問的URL 以.html結尾時, 判斷是否存在該文件, 若是不存在就重寫爲訪問同名的 PHP 腳本。

 

return 指令

語法:
return code複製代碼
應用環境:  server, location, if
該指令用於結束規則的執行並返回狀態碼給客戶端。
例如:
return 403;

 

location 指令

語法: 
location [flags] regex
應用環境: server

flags 包括:

  • ~: 執行一個正則匹配, 區分大小寫
  • ~*: 執行一個正則匹配, 不區分大小寫
  • ^~: 表示普通字符匹配. 使用前綴匹配成功. 若是匹配成功, 則再也不匹配其餘 location.
  • =: 進行普通字符徹底匹配.
優先級:
  • =的優先級最高. 匹配成功後, 再也不匹配其餘項.
  • ^~類型表達式. 匹配成功後, 再也不匹配其餘項.
  • ~和~*. 若是有多個 location 的正則匹配.
  • 常規字符串匹配類型, 按前綴匹配.

 

rewrite_log 指令

語法: 
rewrite_log on|off
應用環境:  server, location, if
啓用時, 將在error_log中記錄 notice 級別的重寫日誌.

 

set 指令

語法:
set variable value
應用環境:  server, location, if
爲給定的變量設置一個特定值。

 

Nginx 內置的全局變量

$args: 這個變量等於請求行中的參數, 同 $query_string.
  • $content_length: 請求頭中的 Content-length 字段.
  • $content_type: 請求頭中的 Content-Type 字段.
  • $document_root: 當前請求在 root 指令中指定的值.
  • $host: 請求主機頭字段,不然爲服務器名稱.
  • $http_user_agent: 客戶端 agent 信息.
  • $http_cookie: 客戶端 cookie 信息.
  • $limit_rate: 這個變量能夠限制鏈接速率.
  • $request_method: 客戶端請求的動做,一般爲 GET 或 POST.
  • $remote_addr: 客戶端的 IP 地址.
  • $remote_port: 客戶端的端口.
  • $remote_user: 已經通過 Auth Basic Module 驗證的用戶名.
  • $request_filename: 當前請求的文件路徑, 由 root 或 alias 指令與 URI 請求生成.
  • $scheme: HTTP 方法(如 http, https).
  • $server_protocol: 請求使用的協議, 一般是HTTP/1.0 或 HTTP/1.1.
  • $server_addr: 服務器地址, 在完成一次系統調用後能夠肯定這個值.
  • $server_name: 服務器名稱.
  • $server_port: 請求到達服務器的端口號.
  • $request_uri: 包含請求參數的原始 URI, 不包含主機名, 如: 」/foo/bar.php?arg=baz」.
  • $uri: 不帶請求參數的當前 URI, $uri 不包含主機名, 如 "/foo/bar.html".
  • $document_uri: 與$uri相同.

 

1

相關文章
相關標籤/搜索