Nginx Rewrite相關功能

Nginx Rewrite相關功能

Nginx服務器利用ngx_http_rewrite_module 模塊解析和處理rewrite請求,此功能依靠 PCRE(perl compatible regularex pression),所以編譯以前要安裝PCRE庫,rewrite是nginx服務器的重要功能之一,用於實現URL的重寫,URL的重寫是很是有用的功能,好比它能夠在咱們改變網站結構以後,不須要客戶端修改原來的書籤,也無需其餘網站修改咱們的連接,就能夠設置爲訪問,另外還能夠在必定程度上提升網站的安全性。前端

ngx_http_rewrite_module模塊指令:

Nginx rewrite模塊介紹node

if指令:

用於條件匹配判斷,並根據條件判斷結果選擇不一樣的Nginx配置,能夠配置在server或location塊中進行配置,Nginx的if語法僅能使用if作單次判斷,不支持使用if else或者if elif這樣的多重判斷。
  • 用法以下:
if (條件匹配) {
        action
    }

使用正則表達式對變量進行匹配,匹配成功時if指令認爲條件爲true,不然認爲false,變量與表達式之間使用如下符號連接:nginx

=: #比較變量和字符串是否相等,相等時if指令認爲該條件爲true,反之爲false。
!=: #比較變量和字符串是否不相等,不相等時if指令認爲條件爲true,反之爲false。
~: #表示在匹配過程當中區分大小寫字符,(能夠經過正則表達式匹配),知足匹配條件爲真,不知足爲假。
!~:#爲區分大小寫字符且匹配結果不匹配,不知足爲真,知足爲假。
~*: #表示在匹配過程當中不區分大小寫字符,(能夠經過正則表達式匹配),知足匹配條件爲真,不知足爲假。
!~*: #爲不區分大小字符且匹配結果不匹配,知足爲假,不知足爲真。
-f 和 ! -f: #判斷請求的文件是否存在和是否不存在
-d 和 ! -d: #判斷請求的目錄是否存在和是否不存在。
-x 和 ! -x: #判斷文件是否可執行和是否不可執行。
-e 和 ! -e: #判斷請求的文件或目錄是否存在和是否不存在(包括文件,目錄,軟連接)。
  1. nginx 的配置文件中支持 if 條件判斷功能,當知足條件時實現特定的配置或者功能,下面咱們使用 echo 演示一下下面咱們修改一下 nginx 默認的主配置文件,location 中添加一個 if 判斷語句塊,若是請求協議爲 http,則執行 echo 語句
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
server {
        listen      80;
        server_name www.OpengSD.net;
        charset utf-8;
        error_page 500 502 503 504 404 =1000 /error.html;
        #access_log /data/nginx/logs/www-taotaobao-net_access.log;
        error_log /data/nginx/logs/www-taotaobao-net_error.log;
        location = /error.html {
                root html;
        }
# if配置段
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( $scheme = http ){
                echo "if-----> $scheme";
                }
        }
}
[root@ubuntu ~]#systemctl reload nginx.service
  • 測試訪問
    在這裏插入圖片描述
  1. 下面我將 if 語句中的等號 「=」, 改成 「!=」 , 因爲 nginx 的 scheme 爲 http 因此判斷不匹配,沒有進行 echo 語句的執行,因此返回默認頁面。
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( $scheme != http ){
                echo "if-----> $scheme";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 測試訪問
    在這裏插入圖片描述
  1. 演示使用正則表達式區分和不區分大小寫進行匹配
# 區分大小寫
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( $scheme ~ http ){
                echo "if-----> $scheme";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service

# 不區分大小寫
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( $scheme ~* http ){
                echo "if-----> $scheme";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 區分大小寫測試
    在這裏插入圖片描述
  • 不區分大小寫測試
    在這裏插入圖片描述
  1. 一樣使用正則表達式時,也可使用歎號 "!" 取反。(不取反看,示例3的區分大小寫)
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( $scheme !~ http ){
                echo "if-----> $scheme";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 取反測試
    在這裏插入圖片描述
  1. 下面咱們使用一下 -f 來判斷指定文件是否存在。
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -f /data/nginx/html/pc/index.html ){
                echo "index.html page is in the /apps/nginx/html/index.html";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 判斷文件存在打印echo字段
    在這裏插入圖片描述
  • 取反判斷文件存在則不打印
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( !-f /data/nginx/html/pc/index.html ){
                echo "index.html page is in the /apps/nginx/html/index.html";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 取反測試
    在這裏插入圖片描述
  1. 使用 -d 選項判斷指定的文件夾是否存在
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -d /data/xxxx ){
                echo "nginx working dir is /data/xxxx";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# /data下是沒有xxxx目錄的
[root@ubuntu ~]#ll /data/
total 1040
drwxr-xr-x  4 root root    4096 Jan 10 20:36 ./
drwxr-xr-x 25 root root    4096 Jan  5 17:17 ../
drwx------  2 root root   16384 Jan  3 20:02 lost+found/
drwxr-xr-x  6 root root    4096 Jan  9 17:57 nginx/
-rw-r--r--  1 root root 1032630 Dec 30 18:49 nginx-1.16.1.tar.gz
  • 測試沒有這個目錄返回默認頁面
    在這裏插入圖片描述
  • 改成已經存在目錄
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -d /data/nginx ){
                echo "nginx working dir is /data/nginx";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# /data下是沒有xxxx目錄的
[root@ubuntu ~]#ll /data/
total 1040
drwxr-xr-x  4 root root    4096 Jan 10 20:36 ./
drwxr-xr-x 25 root root    4096 Jan  5 17:17 ../
drwx------  2 root root   16384 Jan  3 20:02 lost+found/
drwxr-xr-x  6 root root    4096 Jan  9 17:57 nginx/
-rw-r--r--  1 root root 1032630 Dec 30 18:49 nginx-1.16.1.tar.gz
  • 測試
    在這裏插入圖片描述
  1. 判斷指定文件是否具備可執行權限
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -x /data/nginx/html/pc/index.html ){
                echo "index.html can not exec";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# 沒有執行權限
[root@ubuntu ~]#ll /data/nginx/html/pc/index.html 
-rw-r--r-- 1 root root 176 Jan  5 18:51 /data/nginx/html/pc/index.html
  • 測試
    在這裏插入圖片描述
  • 能夠取反測試
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( !-x /data/nginx/html/pc/index.html ){
                echo "index.html can not exec";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 測試
    在這裏插入圖片描述
  1. 使用 -e 選項判斷指定文件、目錄、軟鏈接文件是否存在
# 判斷存在的目錄
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -e /bin ){
                echo "/bin is a symbolic";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# 判斷不存在的目錄
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( -e /xiaobawang ){
                echo "/xiaobawang is a symbolic";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# 取反判斷不存在的目錄
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
            if ( !-e /xiaobawang ){
                echo "/xiaobawang is a symbolic";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 判斷存在的目錄
    在這裏插入圖片描述
  • 判斷不存在的目錄
    在這裏插入圖片描述
  • 取反判斷不存在的目錄
    在這裏插入圖片描述
  1. if 中的判斷條件爲字符串時結果爲 true,字符串爲空時結果爲 false
# 字符串非空
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
                set $xiaobawang "xiaobawang";
        if ( $xiaobawang ){
                echo "string is true";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
# 字符串爲空
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
                set $xiaobawang "";
        if ( $xiaobawang ){
                echo "string is true";
                }
        }
[root@ubuntu ~]#systemctl reload nginx.service
  • 字符串不爲空測試
    在這裏插入圖片描述
  • 字符串爲空測試
    在這裏插入圖片描述

set指令:

指定key並給其定義一個變量,變量能夠調用Nginx內置變量賦值給key,另外set定義格式爲set $key $value,及不管是key仍是value都要加$符號。
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf 
        location /main {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
                set $name magedu;
                echo $name;
                set $my_port $server_port;   # $server_port 是當前端口。
                echo $my_port;
        }
[root@ubuntu ~]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
[root@ubuntu ~]#systemctl reload nginx.service
  • 訪問效果
    在這裏插入圖片描述

break指令:

用於中斷當前相同做用域(location)中的其餘Nginx配置,與該指令處於同一做用域的Nginx配置中,位於它前面的配置生效,位於後面的指令配置就再也不生效了,Nginx服務器在根據配置處理請求的過程當中遇到該指令的時候,回到上一層做用域繼續向下讀取配置,該指令能夠在server塊和location塊以及if塊中使用。git

  • 使用語法以下:
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf 
        location / {
                root /data/nginx/html/pc;
                index index.html;
                default_type text/html;
                set $name magedu;
                echo $name;
                break;  # 中斷指令
                set $my_port $server_port;
                echo $my_port;
        }
[root@ubuntu ~]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
[root@ubuntu ~]#systemctl reload nginx.service
  • 和上一個set指令對比訪問效果(break後面的參數被中斷,前面的照常打印。)
    在這裏插入圖片描述

return指令:

從nginx版本0.8.2開始支持,return用於完成對請求的處理,並直接向客戶端返回響應狀態碼,好比其能夠指定重定向URL(對於特殊重定向狀態碼,301/302等) 或者是指定提示文本內容(對於特殊狀態碼403/500等),處於此指令後的全部配置都將不被執行,return能夠在server、if和location塊進行配置。web

  • 用法以下:
return code; #返回給客戶端指定的HTTP狀態碼
        return code (text); #返回給客戶端的狀態碼及響應體內容,能夠調用變量
        return code URL; #返回給客戶端的URL地址
  • 示例:
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf 
        location / {
                root /data/nginx/html/pc;
                default_type text/html;
                index index.html;
        if ( $scheme = http ){
                #return 666;
                #return 666 "not allow http";        # 指定提示文本內容
                #return 301 http://www.baidu.com;    # 指定重定向URL
                return 500 "service error";
                echo "if-----> $scheme"; #return後面的將再也不執行
                }
        if ( $scheme = https ){
                echo "if ----> $scheme";
                }
        }
[root@ubuntu ~]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
[root@ubuntu ~]#systemctl reload nginx.service
  • 測試(返回狀態碼爲500,且return再也不執行)
    在這裏插入圖片描述

rewrite_log指令:

設置是否開啓記錄ngx_http_rewrite_module模塊日誌記錄到error_log日誌文件當中,能夠配置在http、server、location或if當中,須要日誌級別爲notice 。正則表達式

  • 用法示例:
# 修改主配置文件日誌級別
[root@ubuntu ~]#vim /apps/nginx/conf/nginx.conf
error_log  logs/error.log  notice;  # 這條默認是禁用的打開就能夠了。只能這個級別其餘級別不行。
# 修改子配置文件
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf 
location /main {
index index.html;
default_type text/html;
set $name magedu;
echo $name;
rewrite_log on;
break;
set $my_port $server_port;
echo $my_port;
}
# 測試訪問
[root@ubuntu data]#tail -f /apps/nginx/logs/error.log
2019/02/27 15:10:02 [warn] 5815#0: *3 using uninitialized "my_port" variable, client:
192.168.39.1, server: www.opengsd.net, request: "GET /main HTTP/1.1", host:
"www.magedu.net"

rewrite指令:

經過正則表達式的匹配來改變URI,能夠同時存在一個或多個指令,按照順序依次對URI進行匹配,rewrite主要是針對用戶請求的URL或者是URI作具體處理,如下是URL和URI的具體介紹:express

URI(universal resource identifier):通用資源標識符,標識一個資源的路徑,能夠不帶協議。
URL(uniform resource location):統一資源定位符,是用於在Internet中描述資源的字符串,是URI的子集,主要包括傳輸協議(scheme)、主機(IP、端口號或者域名)和資源具體地址(目錄和文件名)等三部分,通常格式爲 scheme://主機名[:端口號][/資源路徑],如:http://www.a.com:8080/path/file/index.html就是一個URL路徑,URL必須帶訪問協議。
每一個URL都是一個URI,可是URI不都是URL。

例如:
http://example.org:8080/path/to/resource.txt #URI/URL
ftp://example.org/resource.txt #URI/URL
/absolute/path/to/resource.txt #URI

rewrite的官方介紹地址:
rewrite能夠配置在server、location、if,其具體使用方式爲:json

rewrite regex replacement [flag];

rewrite將用戶請求的URI基於regex所描述的模式進行檢查,匹配到時將其替換爲表達式指定的新的URI。 注意:若是在同一級配置塊中存在多個rewrite規則,那麼會自下而下逐個檢查;被某條件規則替換完成後,會從新一輪的替換檢查,隱含有循環機制,但不超過10次;若是超過,提示500響應碼,[flag]所表示的標誌位用於控制此循環機制,若是替換後的URL是以http://或https://開頭,則替換結果會直接以重向返回給客戶端, 即永久重定向301。ubuntu

rewrite flag使用介紹:

利用nginx的rewrite的指令,能夠實現url的從新跳轉,rewrtie有四種不一樣的flag,分別是redirect(臨時重定向)、permanent(永久重定向)、break和last。其中前兩種是跳轉型的flag,後兩種是代理型,跳轉型是指有客戶端瀏覽器從新對新地址進行請求,代理型是在WEB服務器內部實現跳轉的。

Syntax: rewrite regex replacement [flag]; #經過正則表達式處理用戶請求並返回替換後的數據包。 Default: —
Context: server, location, if

redirect;
#臨時重定向,重寫完成後以臨時重定向方式直接返回重寫後生成的新URL給客戶端,由客戶端從新發起請求;使用相
對路徑,或者http://或https://開頭,狀態碼:302

permanent;
#重寫完成後以永久重定向方式直接返回重寫後生成的新URL給客戶端,由客戶端從新發起請求,狀態碼:301
last;

#重寫完成後中止對當前URI在當前location中後續的其它重寫操做,然後對新的URL啓動新一輪重寫檢查,不建議
在location中使用
break;

#重寫完成後中止對當前URL在當前location中後續的其它重寫操做,然後直接將匹配結果返還給客戶端即結束循環
並返回數據給客戶端,建議在location中使用

rewrite案例-域名永久與臨時重定向:

要求:因業務須要,將訪問源域名 www.opengsd.net 的請求永久重定向到www.opengsd.com
臨時重定向不會緩存域名解析記錄(A記錄),可是永久重定向會緩存。

[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location / {
        root /data/nginx/html/pc;
        index index.html;
        rewrite / http://www.jd.com permanent; # 永久重定向 狀態碼301
        #rewrite / http://www.jd.com redirect; # 臨時重定向 狀態碼302
        }
# 語法檢查
[root@ubuntu ~]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
# 從新加載配置
[root@ubuntu ~]#/apps/nginx/sbin/nginx -s reload
  • 臨時重定向測試
    在這裏插入圖片描述
  • 永久重定向測試
    在這裏插入圖片描述
    rewrite沒通過判斷直接使用時用可能在同一個協議的狀況下會進行死循環,應注意直接寫在server裏會有問題最好寫在if判斷下面。(這個是官方的文檔說明)
    在這裏插入圖片描述

永久重定向:

域名永久重定向,京東早期的域名 www.360buy.com 因爲與360公司相似,因而後期永久重定向到了 www.jd.com,永久重定向會緩存DNS解析記錄。
在這裏插入圖片描述

臨時重定向:

域名臨時重定向,告訴瀏覽器域名不是固定重定向到當前目標域名,後期可能隨時會更改,所以瀏覽器不會緩存當前域名的解析記錄,而瀏覽器會緩存永久重定向的DNS解析記錄,這也是臨時重定向與永久重定向最大的本質區別。
在這裏插入圖片描述

rewrite案例--brak與last:

要求:訪問about的請求被轉發至images,而訪問images傳遞請求再次被轉發至images1,以此測試last和break分別有什麼區別:

break案例:

break測試案例:當客戶端訪問break的時候,測試經過rewrite將URL重寫爲test1,而後再經過rewrite將test1重寫爲test2測試兩條write規則最終哪一條生效,而且測試重寫後的URL會不會到其餘location從新匹配。

  1. 配好測試環境和規則(使用curl 命令測試 -L 跟隨跳轉 --head 顯示頭部報文信息)
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /break {
        #return 666 "break";
        root /data/nginx;
        index index.html;
        rewrite ^/break/(.*) /test1/$1 break;  # break匹配成功後再也不向下匹配,也不會跳轉到其餘的location,即直接結束匹配並給客戶端返回結果數據。
        rewrite ^/test1/(.*) /test2/$1 break;  # break不會匹配後面的rewrite規則也不匹配其餘location
        }
        location = /test1 {
        return 999 "new test1";
        #index index.html;
        #root /data/nginx;
        }
        location = /test2 {
        return 666 "new test2";
        #root /opt/nginx;
        #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 
# 測試下面兩個location的顯示
[root@centos7 ~]#curl -L http://www.opengsd.net/test1
new test1[root@centos7 ~]#curl -L http://www.opengsd.net/test2
new test2[root@centos7 ~]#


# 建立break目錄測試頁面
[root@ubuntu ~]#mkdir /data/nginx/break
[root@ubuntu ~]#echo "break html" > /data/nginx/break/index.html

# 建立連個test資源目錄並寫入內容(測試方便)
[root@ubuntu ~]#mkdir /data/nginx/test1
[root@ubuntu ~]#mkdir /data/nginx/test2
[root@ubuntu ~]#echo "test1"  > /data/nginx/test1/index.html
[root@ubuntu ~]#echo "test2"  > /data/nginx/test2/index.html
  1. 測試不加rewrite重寫
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /break {
        #return 666 "break";
        root /data/nginx;
        index index.html;
        #rewrite ^/break/(.*) /test1/$1 break;
        #rewrite ^/test1/(.*) /test2/$1 break;  # 這兩行註釋掉
        }
        location = /test1 {
        return 999 "new test1";
        #index index.html;
        #root /data/nginx;
        }
        location = /test2 {
        return 666 "new test2";
        #root /opt/nginx;
        #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 
# 測試
## 這是沒建立目錄以前找不到資源
[root@centos7 ~]#curl -L http://www.opengsd.net/break
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.16.1</center>
</body>
</html>

## 建立完目錄和測試頁面
[root@centos7 ~]#curl -L http://www.opengsd.net/break
break html
  1. 只加一條的rewrite重寫
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /break {
        #return 666 "break";
        root /data/nginx;
        index index.html;
        rewrite ^/break/(.*) /test1/$1 break;
        #rewrite ^/test1/(.*) /test2/$1 break;
        }
        location = /test1 {
        return 999 "new test1";
        #index index.html;
        #root /data/nginx;
        }
        location = /test2 {
        return 666 "new test2";
        #root /opt/nginx;
        #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 

# 測試(訪問的試break下的index.html可是顯示的倒是test1的index.html內容,說明rewrite重寫成功)
[root@centos7 ~]#curl -L http://www.opengsd.net/break/index.html
test1
[root@centos7 ~]#curl --head http://www.opengsd.net/break/index.html
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 15 Jan 2020 09:04:54 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6
Last-Modified: Wed, 15 Jan 2020 08:57:19 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5e1ed3ef-6"
Accept-Ranges: bytes
  1. 咱們打開以前寫好的另外一條規則(兩條規則都存在可是第一條後面加了break,本條location內的以後的操做都不進行)
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /break {
        #return 666 "break";
        root /data/nginx;
        index index.html;
        rewrite ^/break/(.*) /test1/$1 break;
        rewrite ^/test1/(.*) /test2/$1 break;
        }
        location = /test1 {
        return 999 "new test1";
        #index index.html;
        #root /data/nginx;
        }
        location = /test2 {
        return 666 "new test2";
        #root /opt/nginx;
        #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 

# 測試訪問
[root@centos7 ~]$curl -L http://www.opengsd.net/break/index.html
test1
#最終的結果不會超出break的location並且不會繼續匹配當前location後續的write規則,並且直接返回數據給客戶端。
  1. break適用於不改變客戶端訪問方式,可是要將訪問的目的URL作單次重寫的場景,好比有V1/V2兩個版本的網站前端頁面並存,舊版本的網站數據已經保存到了statics不能丟失,可是要將訪問新版本的資源重寫到新的靜態資源路徑到新的目錄static:
location /statics {
        root /data/nginx;
        index index.html;
        rewrite ^/statics/(.*) /static/$1 break;
}
  • 其實阿里雲的控制檯裏面就能夠區分這一點
  • 新版阿里雲控制檯
    在這裏插入圖片描述
  • 舊版阿里雲控制檯(URL路徑沒有改變過,可是訪問的內容卻不同)
    在這裏插入圖片描述

last案例:

last:對某個location的URL匹配成功後會中止當前location的後續rewrite規則,並結束當前location,而後將匹配生成的新URL跳轉至其餘location繼續匹配,直到沒有location可匹配後將最後一次location的數據返回給客戶端。

  1. 準備測試環境和規則
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /last {
                root /data/nginx;
                index index.html;
                #rewrite ^/last/(.*) /test1/$1 last;
                #rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test1 {
                #return 999 "new test1";
                root /data/nginx;
                index index.html;
                rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test2 {
                return 666 "new test2";
                #root /opt/nginx;
                #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 
# 建立資源頁面
[root@ubuntu ~]#mkdir /data/nginx/last
[root@ubuntu ~]#echo "last" > /data/nginx/last/index.html


# 測試在訪問last資源時打開test1的rewrite規則會匹配到哪裏
[root@centos7 ~]$curl -L http://www.opengsd.net/last/index.html  # 由於上面規則沒有打開因此訪問last資源後面的這個rewrite不生效
last
# 訪問test1測試(這裏的規則會生效)
[root@centos7 ~]$curl -L http://www.opengsd.net/test1/index.html
new test2[root@centos7 ~]$
  1. 多個location來回匹配
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /last {
                root /data/nginx;
                index index.html;
                rewrite ^/last/(.*) /test1/$1 last;
                #rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test1 {
                #return 999 "new test1";
                root /data/nginx;
                index index.html;
                rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test2 {
                return 666 "new test2";
                #root /opt/nginx;
                #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 
# 測試結果上一個locatin 的rewrite生效重寫到test1,test1的rewrite生效重寫到test2。
[root@centos7 ~]$curl -L http://www.opengsd.net/last/index.html
new test2[root@centos7 ~]$
  1. 單條location裏面多個rewrite除了第一條以後的都不會生效
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /last {
                root /data/nginx;
                index index.html;
                rewrite ^/last/(.*) /test1/$1 last;
                rewrite ^/test1/(.*) /test2/$1 last;
                # www.opengsd.net/last/index.html ---> www.opengsd.net/test1/index.html  # 這裏是把訪問的URL重寫,而後到下面的location去匹配,若是下面的location還有rewrite規則,則再次去匹配直到沒有能夠匹配的。
        }
        location /test1 {
                #return 999 "new test1";
                root /data/nginx;
                index index.html;
                #rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test2 {
                return 666 "new test2";
                #root /opt/nginx;
                #index index.html;         
                # 這裏能夠接着定義rewrite規則,可是要有對應的location。
        }
[root@ubuntu ~]#systemctl reload nginx.service 

# 測試第二條的rewrite並無生效
[root@centos7 ~]$curl -L http://www.opengsd.net/last/index.html
test1


# 單個location裏面多個rewrite不會循環,可是會跳出當前location去匹配其餘的location,直到沒有可匹配,而後返回結果到用戶。
  1. last+break配合使用
[root@ubuntu ~]#vim /apps/nginx/conf/conf.d/pc.conf
location /last {
                root /data/nginx;
                index index.html;
                rewrite ^/last/(.*) /test1/$1 last;
                #rewrite ^/test1/(.*) /test2/$1 last;
        }
        location /test1 {
                #return 999 "new test1";
                root /data/nginx;
                index index.html;
                rewrite ^/test1/(.*) /test2/$1 break;  
        }
        location /test2 {
                return 666 "new test2";
                #root /opt/nginx;
                #index index.html;
        }
[root@ubuntu ~]#systemctl reload nginx.service 

# 測試(這裏顯示test2 的內容的緣由是test2下面有這個文件因此會顯示,並且他的匹配規則並無跳出當前的location)
[root@centos7 ~]$curl -L http://www.opengsd.net/last/index.html
test2
# 若是沒有這個目錄或文件則會報錯(說明到上一個rewrite定義的break哪裏就結束了匹配)
[root@ubuntu ~]#rm -f /data/nginx/test2/index.html
[root@centos7 ~]$curl -L http://www.opengsd.net/last/index.html
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.16.1</center>
</body>
</html>
last適用於要不改變客戶端訪問方式可是需作屢次目的URL重寫的場景,場景不是不少。

rewrite案例-自動跳轉https:

要求:基於通訊安全考慮公司網站要求全站https,所以要求將在不影響用戶請求的狀況下將http請求所有自動跳轉至https,另外也能夠實現部分location跳轉。

  1. 生成證書
# 自簽名CA證書
[root@ubuntu certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
Can't load /root/.rnd into RNG
140148192780736:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Generating a RSA private key
.............................................++++
...........................++++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:BeiJing
Locality Name (eg, city) []:BeiJing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:opengsd.net
Organizational Unit Name (eg, section) []:opengsd.net
Common Name (e.g. server FQDN or YOUR name) []:www.opengsd.net
Email Address []:1060351846@qq.com

# 生成證書申請文件
[root@ubuntu certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.opengsd.net.key -out www.opengsd.net.csr
Can't load /root/.rnd into RNG
140607801209280:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/root/.rnd
Generating a RSA private key
...........++++
....................++++
writing new private key to 'www.opengsd.net.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:BeiJing
Locality Name (eg, city) []:BeiJing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:opengsd.net
Organizational Unit Name (eg, section) []:opengsd.net
Common Name (e.g. server FQDN or YOUR name) []:www.opengsd.net
Email Address []:1060351846@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:  # 這個是要給私鑰加密嗎?(爲了方便我沒設置)
An optional company name []:

# 查看生成的證書申請文件
[root@ubuntu certs]#ll
total 24
drwxr-xr-x  2 root  root  4096 Jan 15 18:42 ./
drwxr-xr-x 12 nginx nginx 4096 Jan 15 18:33 ../
-rw-r--r--  1 root  root  2171 Jan 15 18:36 ca.crt
-rw-------  1 root  root  3272 Jan 15 18:35 ca.key
-rw-r--r--  1 root  root  1765 Jan 15 18:42 www.opengsd.net.csr
-rw-------  1 root  root  3272 Jan 15 18:40 www.opengsd.net.key

# 申請簽發證書
[root@ubuntu certs]#openssl x509 -req -days 3650 -in www.opengsd.net.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.opengsd.net.crt
Signature ok
subject=C = CN, ST = BeiJing, L = BeiJing, O = opengsd.net, OU = opengsd.net, CN = www.opengsd.net, emailAddress = 1060351846@qq.com
Getting CA Private Key

# 查看證書內容
[root@ubuntu certs]#openssl x509 -in www.opengsd.net.crt -noout -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            78:e8:d1:d9:e5:6f:37:14:23:61:00:d8:cd:82:fa:b3:23:d8:33:1e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = BeiJing, L = BeiJing, O = opengsd.net, OU = opengsd.net, CN = www.opengsd.net, emailAddress = 1060351846@qq.com
        Validity
            Not Before: Jan 15 10:42:57 2020 GMT
            Not After : Jan 12 10:42:57 2030 GMT
        Subject: C = CN, ST = BeiJing, L = BeiJing, O = opengsd.net, OU = opengsd.net, CN = www.opengsd.net, emailAddress = 1060351846@qq.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
以上的生成和配置證書能夠參考上一篇博客。
  1. 實現https跳轉
[root@ubuntu certs]#vim /apps/nginx/conf/conf.d/pc.conf 
server {
        listen      443 ssl;
        listen      80;
        ssl_certificate /apps/nginx/certs/www.opengsd.net.crt;
        ssl_certificate_key /apps/nginx/certs/www.opengsd.net.key;
        ssl_session_cache shared:sslcache:20m;
        ssl_session_timeout 10m;
        server_name www.OpengSD.net;
        charset utf-8;
        location / {
                root /data/nginx/html/pc;
                index index.html;
        if ($scheme = http ){    #未加條件判斷,會致使死循環
                rewrite / https://www.opengsd.net permanent;
                }
        }
}

[root@ubuntu certs]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
[root@ubuntu certs]#systemctl reload nginx.service 

# 測試直接訪問https
[root@centos7 ~]$curl -L -k -i https://www.opengsd.net/
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 15 Jan 2020 10:53:33 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 15
Last-Modified: Tue, 14 Jan 2020 11:39:27 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5e1da86f-f"
Accept-Ranges: bytes

192.168.39.184

# 訪問http自動跳轉爲https
[root@centos7 ~]$curl -L -k -i http://www.opengsd.net/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.16.1
Date: Wed, 15 Jan 2020 10:56:47 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: https://www.opengsd.net

HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 15 Jan 2020 10:56:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 15
Last-Modified: Tue, 14 Jan 2020 11:39:27 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5e1da86f-f"
Accept-Ranges: bytes

192.168.39.184
  1. 若是是由於規則匹配問題致使的陷入死循環,則報錯以下:
    在這裏插入圖片描述

    rewrite案例-判斷文件是否存在:

    要求:當用戶訪問到公司網站的時輸入了一個錯誤的URL,能夠將用戶重定向至官網首頁。
[root@ubuntu certs]#vim /apps/nginx/conf/conf.d/pc.conf 
        location / {
                root /data/nginx/html/pc;
                index index.html;
        if (!-f $request_filename ){
                rewrite (.*) http://www.opengsd.net/index.html;
                }
        }
[root@ubuntu certs]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx//conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx//conf/nginx.conf test is successful
[root@ubuntu certs]#systemctl reload nginx.service
  • 測試
    在這裏插入圖片描述

Nginx防盜鏈:

  • 防盜鏈基於客戶端攜帶的referer實現,referer是記錄打開一個頁面以前記錄是從哪一個頁面跳轉過來的標記信息,若是別人只連接了本身網站圖片或某個單獨的資源,而不是打開了網站的整個頁面,這就是盜鏈,referer就是以前的那個網站域名,正常的referer信息有如下幾種:
none:請求報文首部沒有referer首部,好比用戶直接在瀏覽器輸入域名訪問web網站,就沒有referer信息。
blocked:請求報文有referer首部,但無有效值,好比爲空。
server_names:referer首部中包含本主機名及即nginx 監聽的server_name。
arbitrary_string:自定義指定字符串,但可以使用*做通配符。
regular expression:被指定的正則表達式模式匹配到的字符串,要使用~開頭,例如: ~.*\.opengsd\.com。
  • 正常經過搜索引擎搜索web 網站並訪問該網站的referer信息以下:
#經過搜索引擎訪問web網站的referer信息:
==> /apps/nginx/logs/access_json.log <==
{"@timestamp":"2019-02-
28T13:58:46+08:00","host":"192.168.39.184","clientip":"192.168.39.1","siz
e":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-
","http_host":"www.opengsd.net","uri":"/index.html","domain":"www.opengsd.net","xff":"-
","referer":"https://www.baidu.com/s?ie=utf-
8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=www.opengsd.net&oq=www.opengsd.net&rsv_pq=d630606800
02eb69&rsv_t=de01TWnmyTdcJqph7SfI1hXgXLJxSSfUPcQ3QkWdJk%2FLNrN95ih3XOhbRs4&rqlang=cn&rsv
_enter=1&inputT=321&rsv_sug3=41&rsv_sug2=0&rsv_sug4=1626","tcp_xff":"","http_user_agent"
:"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/72.0.3626.119 Safari/537.36","status":"304"}

實現web盜鏈:

在一個web 站點盜鏈另外一個站點的資源信息,好比圖片、視頻等。

[root@s2 conf.d]# pwd
/apps/nginx/conf/conf.d
[root@s2 conf.d]# cat mageedu.net.conf
server {
        listen 80;
        server_name www.mageedu.net;

        location / {
        index index.html;
        root "/data/nginx/html/mageedu";
        access_log /apps/nginx/logs/www.mageedu.net.log access_json;
        }
}
#準備盜鏈web頁面:
[root@s2 conf.d]# mkdir /data/nginx/html/mageedu
[root@s2 conf.d]# cat /data/nginx/html/mageedu/index.html
<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>盜鏈頁面</title>
</head>
<body>
<a href="http://www.magedu.net">測試盜鏈</a>
<img src="http://www.magedu.net/images/1.jpg">
</body>
</html>

#重啓Nginx並訪問http://www.mageedu.net/測試
#驗證兩個域名的日誌,是否會在被盜連的web站點的日誌中出現如下盜鏈日誌信息:
==> /apps/nginx/logs/access_json.log <==
{"@timestamp":"2019-02-
28T13:27:37+08:00","host":"192.168.7.102","clientip":"192.168.0.1","size":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.magedu.net","uri":"/images/1.jpg","domain":"www.magedu.net","xff":"-","referer":"http://www.mageedu.net/","tcp_xff":"","http_user_agent":"Mozilla/5.0(Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0","status":"304"}

在這裏插入圖片描述

實現防盜鏈:

基於訪問安全考慮,nginx支持經過ungx_http_referer_module模塊 官網文檔 檢查訪問請求的referer信息是否有效實現防盜鏈功能。

  • 定義方式以下:
[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location /images {
        root /data/nginx/html/pc;
        index index.html;
        valid_referers none blocked server_names
        *.example.com example.* www.example.org/galleries/
        ~\.google\.;
if ($invalid_referer) {
    return 403;
}

# 定義防盜鏈:
location ^~ /images {
        root /data/nginx;
        index index.html;
        valid_referers none blocked server_names *.magedu.com www.magedu.*
api.online.test/v1/hostlist ~\.google\. ~\.baidu\.; #定義有效的referer
        if ($invalid_referer) { #假如是使用其餘的無效的referer訪問:
            return 403; #返回狀態碼403
        }
}
#重啓Nginx並訪問測試
  • 使用瀏覽器訪問盜鏈網站 www.mageedu.net, 驗證是否提早狀態碼403:
    在這裏插入圖片描述 以上呢都是基於本身的理解,可能會有錯誤的地方你們參考便可。
相關文章
相關標籤/搜索