Nginx之rewrite實現(xiàn)URL重寫方式
1.開篇
rewrite是nginx服務(wù)器提供的一個重要功能,用于實現(xiàn)URL的重寫。
例如我們訪問https://aa.qq.com,打開的是https://age.qq.com/,這就是使用URL重寫的特性來實現(xiàn)的。
ngx_http_rewrite_module
為實現(xiàn)URL重寫提供了指令支持。
官方文檔地址:https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
接下來我們來看看rewrite的相關(guān)指令。
2.rewrite相關(guān)指令
2.1 set指令
作用域:server, location, if
語法:set $variable value;
該指令可以設(shè)置一個變量。
$variable
:為變量的名稱,可以看到變量的名稱以$
符號開頭,且不要與nginx預(yù)設(shè)的全局變量名相同。value
:為變量的值,可以是字符串、其他變量或者兩者的組合。
既然自定義的變量名不能與nginx的全局變量名相同,那就有必要了解使用rewrite功能時常用的nginx全局變量。
rewrite常用全局變量
全局變量 | 說明 |
---|---|
$args | 用于獲取請求中的參數(shù)。例如:http://192.168.110.92/test?name=tom&age=18,$args的值就為name=tom&age=18 |
$host | 用于獲取請求中的主機部分的值。例如:http://192.168.110.92/test?name=tom&age=18,$host的值為192.168.110.92。 |
$http_user_agent | 用于獲取請求中的User-Agent字段值 |
$remote_addr | 用于獲取客戶端的IP地址 |
$remote_port | 用于獲取客戶端與服務(wù)器建立連接的端口號 |
$request_method | 用于獲取客戶端的請求方式,例如GET、POST等 |
$request_uri | 用于獲取當(dāng)前請求的URI。例如:http://192.168.110.92/test?name=tom&age=18,$request_uri的值就為/test?name=tom&age=18 |
$query_string | 與$args作用相同 |
$scheme | 用于獲取客戶端請求使用的協(xié)議,例如http、https等 |
$server_addr | 用于獲取服務(wù)端的IP地址 |
$server_name | 用于獲取虛擬主機的名稱 |
$server_port | 用于獲取虛擬主機的監(jiān)聽的端口 |
$document_uri | 用于獲取請求中的當(dāng)前URI。例如:http://192.168.110.92/test?name=tom&age=18,$document_uri的值為/test |
$uri | 與$document_uri作用相同 |
$http_user_agent | 用于獲取請求頭中User-Agent字段的值 |
$request_filename | 當(dāng)前請求的文件路徑 |
下面我們設(shè)置自定義變量,順便體驗使用一下這些全局變量。
location /test { default_type text/html; set $username zhangsan; return 200 <html>><p>username:$username</p><p>request_uri:$request_uri</p><p>document_uri:$document_uri</p><p>uri:$uri</p><p>query_string:$query_string</p><p>args:$args</p></html>; }
發(fā)起請求:http://192.168.110.98/test?name=tom
2.2 if指令
作用域:server, location
語法:if (condition) { … }
如果條件表達式為true,則執(zhí)行該模塊大括號中的指令。
Tips:if
和(
之間有一個空格。
條件表達式有幾種形式:
1)變量名,如果變量的值為空字符串或"0",則為false,其他條件為true。
if ($variable){ }
2)使用"=“和”!="比較變量和字符串是否相等,滿足條件則為true,否則為false。
if ($request_method = POST){ }
3)使用正則表達式與變量的值進行匹配。變量與正則表達式之間使用~
、~*
、!~
、!~*
,如果正則表達式包含}
或;
,則整個表達式應(yīng)該用單引號或雙引號括起來。
~
:表示匹配正則表達式,區(qū)分大小寫~*
:表示匹配正則表達式,不區(qū)分大小寫!~
:表示匹配正則表達式,區(qū)分大小寫,并對匹配后的結(jié)果取反!~*
:表示匹配正則表達式,不區(qū)分大小寫,并對匹配后的結(jié)果取反
if ($http_user_agent ~ Mozilla/5.0){ }
4)判斷文件是否存在:-f
和!-f
if (-f $request_filename){ } if (!-f $request_filename){ }
示例:
location /test { default_type text/html; if (!-f $request_filename){ return 200 "<h1>file not exist</h1>"; } root html; }
我們已經(jīng)在html目錄下準(zhǔn)備了一個test.html。
訪問http://192.168.110.98/test.html,可以正常顯示。
訪問http://192.168.110.98/test,因為文件不存在,所以執(zhí)行if條件塊的指令。
5)判斷目錄是否存在:-d
和!-d
6)判斷文件、目錄或符號鏈接是否存在:-e
和!-e
7)判斷文件是否可以執(zhí)行:-x
和!-x
2.3 break指令
作用域:server, location, if;
語法:break;
在同一作用域中,中斷該指令之后的其他指令,位于其前面的指令配置生效,位于其后面的指令配置則無效。
示例:如果URL中存在參數(shù),則執(zhí)行if邏輯。
location /testBreak { default_type text/plain; set $username lisi; if ($args){ set $username wangwu; break; set $username zhaoliu; } add_header username $username; return 200 $username; }
訪問http://192.168.110.98/testBreak,指令都正常執(zhí)行。
訪問http://192.168.110.98/testBreak?name=zhangsan,說明執(zhí)行了if邏輯。
按break;
語句的定義來說,在其執(zhí)行后,其作用域外后面的指令應(yīng)該正常執(zhí)行才對,但是這里直接返回了404。這個時候,就需要我們查看error.log
。
可以發(fā)現(xiàn),錯誤提示為文件未找到,根據(jù)錯誤提示,我們需要在html目錄下創(chuàng)建一個testBreak目錄,然后在testBreak目錄下創(chuàng)建一個index.html文件
cd /usr/local/nginx mkdir testBreak vim index.html <html> <body>this is testBreak</body> </html>
再次訪問http://192.168.110.98/testBreak?name=zhangsan,可以看到break語句執(zhí)行后,其作用域外后面的指令正常執(zhí)行。
2.4 return指令
作用域:
server
,location
,if
語法:
return code [text];
return code URL;
return URL;
該指令可以停止處理并指定的響應(yīng)碼返回給前端。既可以返回文本,也可以重定向URL。
示例:
location /testReturn { default_type text/plain; return 200 "test return"; }
location /testReturn { return 302 https://www.baidu.com; }
location /testReturn { return https://www.baidu.com; }
2.5 rewrite指令
在了解set
、if
、break
、return
指令后,重頭戲rewrite
指令登場。
作用域:server, location, if;
語法:rewrite regex replacement [flag];
regex
:用來匹配URI的正則表達式。replacement
:正則匹配成功后,用來替換URI的字符串。如果該字符串以http://
、https://
或$scheme
開頭,則處理將停止,并重定向URI到客戶端。flag
:是一個可選參數(shù),其有4個候選值。
flag值 | 說明 |
---|---|
last | 停止處理rewrite指令,并使用重寫的URI去與各個location進行匹配 |
break | 停止處理rewrite指令,與break;效果一致 |
redirect | 如果replacement字符串不是以http://、https://或$scheme開頭,則重定向到重寫的URI,響應(yīng)碼為302 |
permanent | 重定向到重寫的URI,響應(yīng)碼為301 |
rewrite指令通過正則表達式匹配URI,并修改URI??赏瑫r存在多個rewrite指令,按照順序依次對URI進行匹配和處理。
示例:
location /rewrite { rewrite ^/rewrite/aaa\w+$ https://www.baidu.com; rewrite ^/rewrite/(bbb)\w+$ /$1 last; rewrite ^/rewrite/(ccc)\w+$ /$1 break; rewrite ^/rewrite/(ddd)\w+$ /$1 redirect; rewrite ^/rewrite/(eee)\w+$ /$1 permanent; } location /bbb { default_type text/plain; return 200 "this is bbb"; } location /ccc { default_type text/plain; return 200 "this is ccc"; } location /ddd { default_type text/plain; return 200 "this is ddd"; } location /eee { default_type text/plain; return 200 "this is eee"; }
2.6 rewrite_log指令
作用域:http, server, location, if
語法:rewrite_log on | off;
默認值:rewrite_log off;
該指令可以配置是否將ngx_http_rewrite_module
指令的處理結(jié)果以notice
級別的日志寫入到error_log中。
示例:
location /rewrite { # 開啟rewrite_log rewrite_log on; # 配置error_log error_log logs/error.log notice; rewrite ^/rewrite/aaa\w+$ https://www.baidu.com; rewrite ^/rewrite/(bbb)\w+$ /$1 last; rewrite ^/rewrite/(ccc)\w+$ /$1 break; rewrite ^/rewrite/(ddd)\w+$ /$1 redirect; rewrite ^/rewrite/(eee)\w+$ /$1 permanent; }
這樣我們就可以在error.log中看到notice級別的日志。
3.使用場景
在熟悉了ngx_http_rewrite_module
的相關(guān)指令后,我們來看看rewrite的相關(guān)使用場景。
3.1 域名重定向
**場景:**公司官網(wǎng)上線的時候地址為www.aaa.com,隨著公司的不斷發(fā)展,需要將官網(wǎng)地址升級為www.bbb.com,但是需要在訪問www.aaa.com能夠自動跳轉(zhuǎn)到www.bbb.com。
Tips:www.aaa.com和www.bbb.com需要指向同一IP。
**解決方案:**使用rewrite指令重寫URI。
server { listen 80; server_name www.aaa.com; rewrite ^(.*) https://www.bbb.com$1; }
3.2 優(yōu)雅處理防盜鏈
前面我們在【Nginx靜態(tài)資源防盜鏈】一文中已經(jīng)簡單的實現(xiàn)了靜態(tài)資源的防盜鏈,但是展示在頁面的是一個裂開的小圖片,不夠美觀。
我們可以如下配置:
location ~^/.*\.(jpg|jpg|gif|jfif) { valid_referers www.example.com; if ($invalid_referer){ rewrite ^/ http://192.168.110.98/images/forbidden.jpg; } root html; }
如果出現(xiàn)盜鏈的情況,將會出現(xiàn)類似于如下效果:
總結(jié)
以上就是Nginx之rewrite實現(xiàn)URL重寫,Nginx是多模塊化的,還有很多高級功能,我們后面繼續(xù)探索。
這些僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
nginx調(diào)用php-fpm出錯解決方法和nginx配置詳解
這篇文章介紹了nginx調(diào)用php-fpm出錯的解決方法,最后給出了nginx配置方法,需要的朋友可以參考下2014-03-03nginx設(shè)置X-Frame-Options的字段選擇
本文主要介紹了X-Frame-Options選項的三個值,包含DENY、SAMEORIGIN和ALLOW-FROM uri,具有一定的參考價值,感興趣的可以了解一下2024-12-12