整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          Nginx的Rewrite規(guī)則與實例

          Nginx的Rewrite規(guī)則與實例

          ginx的Rewrite規(guī)則與實例

          Nginx Rewrite 規(guī)則相關(guān)指令

          相關(guān)指令有if,rewrite,set,return,break等,其中最關(guān)鍵的就是rewrite.一個簡單的Nginx Rewrite規(guī)則語法如下:

          rewrite ^/b/(.*)\.html /play.php?video=break;

          1.break指令

          默認值:none ;使用環(huán)境:server,location,if ;

          該指令的作用是完成當(dāng)前的規(guī)則集,不再處理rewrite指令。

          2.if指令

          默認值:none ;使用環(huán)境:server,location

          該指令用于檢查一個條件是否符合,如果條件符合,則執(zhí)行大括號內(nèi)的語句。If指令不支持嵌套,不支持多個條件&&和||處理。

          A.變量名,錯誤的值包括:空字符串""或者任何以0開始的字符串

          B.變量比較可以使用"="(表示等于)和"!="(表示不等于)

          C.正則表達式模式匹配可以使用"~*"和"~"符號

          D."~"符號表示區(qū)分大小寫字母的匹配

          E."~*"符號表示不區(qū)分大小寫字母的匹配

          F."!~"和"!~*"符號的作用剛好和"~"、"~*"相反,表示不匹配

          G."-f"和"!-f"用來判斷文件是否存在

          H."-d"和"!-d"用來判斷目錄是否存在

          I."-e"和"!-e"用來判斷文件或目錄是否存在

          J."-x"和"!-x"用來判斷文件是否為可執(zhí)行

          K.部分正則表達式可以在()內(nèi),用~來訪問

          3.return指令

          語法:return code ;使用環(huán)境:server,location,if ;

          該指令用于結(jié)束規(guī)則的執(zhí)行并返回狀態(tài)碼給客戶端。

          示例:如果訪問的URL以".sh"或".bash"結(jié)尾,則返回403狀態(tài)碼

          location ~ .*\.(sh|bash)?$

          {

          return 403;

          }

          ginx_Rewrite

          • 一、介紹Rewrite

          Rewrite根據(jù)nginx提供的全局變量或自己設(shè)置的變量,結(jié)合正則表達式和標(biāo)志位實現(xiàn)url重寫和者重定向。

        1. Rewrite和location類似,都可以實現(xiàn)跳轉(zhuǎn),區(qū)別是rewrite是在同一域名內(nèi)更改url,而location是對同類型匹配路徑做控制訪問,或者proxy_pass代理到其他服務(wù)器。
        2. Rewrite和location執(zhí)行順序:執(zhí)行server下的rewrite執(zhí)行l(wèi)ocation匹配執(zhí)行l(wèi)ocation下的rewrite

        3. 二、語法和參數(shù)說明

          • rewrite語法格式
          rewrite        <regex>        <replacement>        <flag>;
           關(guān)鍵字        正則表達式         代替的內(nèi)容         重寫類型
          
          Rewrite:一般都是rewrite
          Regex:可以是字符串或者正則來表示想要匹配的目標(biāo)URL
          Replacement:將正則匹配的內(nèi)容替換成replacement
          Flag:flag標(biāo)示,重寫類型:
            - last:本條規(guī)則匹配完成后,繼續(xù)向下匹配新的location URI規(guī)則;相當(dāng)于Apache里德(L)標(biāo)記,表示完成rewrite,瀏覽器地址欄URL地址不變;一般寫在server和if中;
            - break:本條規(guī)則匹配完成后,終止匹配,不再匹配后面的規(guī)則,瀏覽器地址欄URL地址不變;一般使用在location中;
            - redirect:返回302臨時重定向,瀏覽器地址會顯示跳轉(zhuǎn)后的URL地址;
            - permanent:返回301永久重定向,瀏覽器地址欄會顯示跳轉(zhuǎn)后的URL地址;
          server {
            # 訪問 /last.html 的時候,頁面內(nèi)容重寫到 /index.html 中,并繼續(xù)后面的匹配,瀏覽器地址欄URL地址不變
            rewrite /last.html /index.html last;
          
            # 訪問 /break.html 的時候,頁面內(nèi)容重寫到 /index.html 中,并停止后續(xù)的匹配,瀏覽器地址欄URL地址不變;
            rewrite /break.html /index.html break;
          
            # 訪問 /redirect.html 的時候,頁面直接302定向到 /index.html中,瀏覽器地址URL跳為index.html
            rewrite /redirect.html /index.html redirect;
          
            # 訪問 /permanent.html 的時候,頁面直接301定向到 /index.html中,瀏覽器地址URL跳為index.html
            rewrite /permanent.html /index.html permanent;
          
            # 把 /html/*.html=> /post/*.html ,301定向
            rewrite ^/html/(.+?).html$ /post/$1.html permanent;
          
            # 把 /search/key=> /search.html?keyword=key
            rewrite ^/search\/([^\/]+?)(\/|$) /search.html?keyword=$1 permanent;
            
            # 把當(dāng)前域名的請求,跳轉(zhuǎn)到新域名上,域名變化但路徑不變
            rewrite ^/(.*) http://www.jd.com/$1 permanent;
            }
          if (表達式) {
          }
          
          #當(dāng)表達式只是一個變量時,如果值為空或任何以0開頭的字符串都會當(dāng)做false直接比較變量和內(nèi)容時,使用=或!=~正則表達式匹配,~*不區(qū)分大小寫的匹配,!~區(qū)分大小寫的不匹配
          
          $args :這個變量等于請求行中的參數(shù),同$query_string
          $content_length : 請求頭中的Content-length字段。
          $content_type : 請求頭中的Content-Type字段。
          $document_root : 當(dāng)前請求在root指令中指定的值。
          $host : 請求主機頭字段,否則為服務(wù)器名稱。
          $http_user_agent : 客戶端agent信息
          $http_cookie : 客戶端cookie信息
          $limit_rate : 這個變量可以限制連接速率。
          $request_method : 客戶端請求的動作,通常為GET或POST。
          $remote_addr : 客戶端的IP地址。
          $remote_port : 客戶端的端口。
          $remote_user : 已經(jīng)經(jīng)過Auth Basic Module驗證的用戶名。
          $request_filename : 當(dāng)前請求的文件路徑,由root或alias指令與URI請求生成。
          $scheme : HTTP方法(如http,https)。
          $server_protocol : 請求使用的協(xié)議,通常是HTTP/1.0或HTTP/1.1。
          $server_addr : 服務(wù)器地址,在完成一次系統(tǒng)調(diào)用后可以確定這個值。
          $server_name : 服務(wù)器名稱。
          $server_port : 請求到達服務(wù)器的端口號。
          $request_uri : 包含請求參數(shù)的原始URI,不包含主機名,如:”/foo/bar.php?arg=baz”。
          $uri : 不帶請求參數(shù)的當(dāng)前URI,$uri不包含主機名,如”/foo/bar.html”。
          $document_uri : 與$uri相同。
           
          例子:
          URL:http://localhost:81/download/stat.php?id=1585378&web_id=1585378
          Server_Dir:/var/www/html
          $host:localhost
          $server_port:81
          $request_uri:/download/stat.php?id=1585378&web_id=1585378
          $document_uri:/download/stat.php
          $document_root:/var/www/html
          $request_filename:/var/www/html/download/stat.php
          
          # 如果文件不存在則返回400
          if (!-f $request_filename) {
              return 400;
          }
          
          # 如果host是www.360buy.com,則301到www.jd.com中
          if ( $host !="www.jd.com" ){
              rewrite ^/(.*)$ https://www.jd.com/$1 permanent;
          }
          
          # 如果請求類型是POST則返回405,return不能返回301,302
          if ($request_method=POST) {
              return 405;
          }
          
          # 如果參數(shù)中有 a=1 則301到指定域名
          if ($args ~ a=1) {
              rewrite ^ http://example.com/ permanent;
          }
          - 文件名及參數(shù)重寫
           location=/index.html {
           # 修改默認值為
           set $name test;
          
           # 如果參數(shù)中有 name=xx 則使用該值
           if ($args ~* name=(\w+?)(&|$)) {
               set $name $1;
           }
          
           # permanent 301重定向
           rewrite ^ /$name.html permanent;
          }
          
          - 隱藏真實目錄
          server {
            root /var/www/html;
            # 用 /html_test 來掩飾 html
            location / {
                # 使用break拿一旦匹配成功則忽略后續(xù)location
                rewrite /html_test /html break;
            }
          
            # 訪問真實地址直接報沒權(quán)限
            location /html {
                return 403;
            }
          }


          - 禁止指定IP訪問
           location / {
                  if ($remote_addr=192.168.1.253) {
                          return 403;
                  }
           }
          - 如果請求的文件不存在,則反向代理到localhost 。這里的break也是停止繼續(xù)rewrite
          if (!-f $request_filename){
              break;
              proxy_pass http://127.0.0.1;
          }
          - 對/images/bla_500x400.jpg文件請求,重寫到/resizer/bla.jpg?width=500&height=400地址,并會繼續(xù)嘗試匹配location。
          rewrite ^/images/(.*)_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=$3? last;


          Proxy_Pass

          Proxy_pass反向代理,用的是nginx的Proxy模塊。

          第一種:
          location /proxy/ {
              proxy_pass http://127.0.0.1/;
          }
          代理到URL:http://127.0.0.1/test.html
          
          
          第二種:
          location /proxy/ {
              proxy_pass http://127.0.0.1;  #少/
          }
          代理到URL:http://127.0.0.1/proxy/test.html
          
          
          第三種:
          location /proxy/ {
              proxy_pass http://127.0.0.1/aaa/;
          }
          代理到URL:http://127.0.0.1/aaa/test.html
          
          
          第四種(相對于第三種,最后少一個 / )
          location /proxy/ {
              proxy_pass http://127.0.0.1/aaa;
          }
          代理到URL:http://127.0.0.1/aaatest.html
          
          - proxy_set_header  Host  $host;  作用web服務(wù)器上有多個站點時,用該參數(shù)header來區(qū)分反向代理哪個域名。比如下邊的代碼舉例。
          - proxy_set_header X-Forwarded-For  $remote_addr; 作用是后端服務(wù)器上的程序獲取訪客真實IP,從該header頭獲取。部分程序需要該功能。
          
          - Proxy_pass配合upstream實現(xiàn)負載均衡
          http {
              include       mime.types;
              default_type  application/octet-stream;
              sendfile        on;
           
              upstream core_tomcat {
                server 192.168.1.253:80      weight=5  max_fails=3 fail_timeout=30;
                server 192.168.1.252:80      weight=1  max_fails=3 fail_timeout=30;
                server 192.168.1.251:80      backup;
              }
          
              server {
                  listen       80;
                  server_name  www.jd.com;
                  location /web {
                      proxy_pass http://core_tomcat;
                      proxy_set_header  Host  $host;
                  }
              }
           }
          

          Nginx負載均衡的幾種模式

          • 輪詢:每個請求按時間順序逐一分配到不同的后端服務(wù)器,如果后端服務(wù)器down掉,就不在分配;
          upstream core_tomcat {
              server 192.168.1.253:80      max_fails=3 fail_timeout=30;
              server 192.168.1.252:80      max_fails=3 fail_timeout=30;
           }
          • 權(quán)重輪詢:根據(jù)后端服務(wù)器性能不通配置輪詢的權(quán)重比,權(quán)重越高訪問的比重越高;
          upstream core_tomcat {
              server 192.168.1.253:80      weight=2  max_fails=3 fail_timeout=30;
              server 192.168.1.252:80      weight=8  max_fails=3 fail_timeout=30;
          }
          #假如有十個請求,八個會指向第二臺服務(wù)器,兩個指向第一臺;
          
          • IP_Hash:根據(jù)請求的ip地址hash結(jié)果進行分配,第一次分配到A服務(wù)器,后面再請求默認還是分配到A服務(wù)器;可以解決Session失效重新登錄問題;
          upstream core_tomcat {
            ip_hash;
            server 192.168.1.253:80      max_fails=3 fail_timeout=30;
            server 192.168.1.252:80      max_fails=3 fail_timeout=30;
          }
          • Fair:按后端服務(wù)器的響應(yīng)時間來分配請求,響應(yīng)時間短的優(yōu)先分配;
          upstream core_tomcat {
            fair;
            server 192.168.1.253:80      max_fails=3 fail_timeout=30;
            server 192.168.1.252:80      max_fails=3 fail_timeout=30;
          }
          
          • Url_hash:按訪問url的hash結(jié)果來分配請求,使每個url定向到同一個后端服務(wù)器,后端服務(wù)器為緩存時比較有效;

          ginx的rewrite模塊指令

          Nginx的rewrite模塊即ngx_http_rewrite_module標(biāo)準(zhǔn)模塊,主要功能是重寫請求URI,也是Nginx默認安裝的模塊。rewrite模塊會根據(jù)PCRE正則匹配重寫URI,然后根據(jù)指令參數(shù)或者發(fā)起內(nèi)部跳轉(zhuǎn)再一次進行l(wèi)ocation匹配,或者直接進行30x重定向返回客戶端。

          rewrite模塊的指令就是一門微型的編程語言,包含set、rewrite、break、if、return等一系列指令。

          set指令

          set指令是由ngx_http_rewrite_module標(biāo)準(zhǔn)模塊提供的,用于向變量存放值。在Nginx配置文件中,變量只能存放一種類型的值,因為只存在一種類型的值,那就是字符串。

          set指令的配置項格式如下:

          set $variable value;

          注意:在Nginx配置文件中,變量定義和使用都要以$開頭。Nginx變量名前面有一個$符號,這是記法上的要求。所有的Nginx變量在引用時必須帶上$前綴。另外,Nginx變量不能與Nginx服務(wù)器預(yù)設(shè)的全局變量同名。比如,我們的nginx.conf文件中有下面這一行配置:

          set $a "hello world";

          上面的語句中,set配置指令對變量$a進行了賦值操作,把字符串hello world賦給了它。也可以直接把變量嵌入字符串常量中以構(gòu)造出新的字符串:

          set $a "foo";
          set $b "$a, $a";

          這個例子通過前面定義的變量$a的值來構(gòu)造變量$b的值,于是這兩條指令順序執(zhí)行完之后,$a的值是"foo",而$b的值則是"foo,foo"。把變量嵌入字符串常量中以構(gòu)造出新的字符串,這種技術(shù)在Linux Shell腳本中常常用到,并且被稱為“變量插值”(VariableInterpolation)。

          set指令不僅有賦值的功能,還有創(chuàng)建Nginx變量的副作用,即當(dāng)作為賦值對象的變量尚不存在時,它會自動創(chuàng)建該變量。比如在上面這個例子中,若$a這個變量尚未創(chuàng)建,則set指令會自動創(chuàng)建$a這個用戶變量。

          Nginx變量一旦創(chuàng)建,其變量名的可見范圍就是整個Nginx配置,甚至可以跨越不同虛擬主機的server配置塊。但是,對于每個請求,所有變量都有一份獨立的副本,或者說都有各變量用來存放值的容器的獨立副本,彼此互不干擾。Nginx變量的生命期是不可能跨越請求邊界的。

          rewrite指令

          rewrite指令是由ngx_http_rewrite_module標(biāo)準(zhǔn)模塊提供的,主要功能是改寫請求URI。rewrite指令的格式如下:

          rewrite regrex replacement [flag];

          如果regrex匹配URI,URI就會被替換成replacement的計算結(jié)果,replacement一般是一個“變量插值”表達式,其計算之后的字符串就是新的URI。

          下面的例子有兩個重新配置項,具體如下:

          location /download/ {
           rewrite ^/download/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 last;
           rewrite ^/download/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb last;
           return 404;
          }
          location /view {
           echo "uri: $uri ";
          }

          在瀏覽器中請求http://crazydemo.com/download/1/video/10,地址發(fā)生了重寫,并且發(fā)生了location的跳轉(zhuǎn),結(jié)果如圖7-17所示。

          圖7-17 輸出結(jié)果

          在這個演示例子中,replacement中的占位變量、的值是指令參數(shù)regrex正則表達式從原始URI中匹配出來的子字符串,也叫正則捕獲組,編號從1開始。

          rewrite指令可以使用的上下文為:server、location、if inlocation。

          如果rewrite同一個上下文中有多個這樣的rewrite重新指令,匹配就會依照rewrite指令出現(xiàn)的順序先后依次進行下去,匹配成功之后并不會終止,而是繼續(xù)往下匹配,直到返回最后一個匹配的為止。如果想要中途中止,不再繼續(xù)往下匹配,可以使用第3個指令參數(shù)flag。flag參數(shù)的值有l(wèi)ast、break、redirect、permanent。

          如果flag參數(shù)使用last值,并且匹配成功,那么停止處理任何rewrite相關(guān)的指令,立即用計算后的新URI開始下一輪的location匹配和跳轉(zhuǎn)。前面的例子使用的就是last參數(shù)值。

          如果flag參數(shù)使用break值,就如同break指令的字面意思一樣,停止處理任何rewrite的相關(guān)指令,但是不進行l(wèi)ocation跳轉(zhuǎn)。

          將上面的rewrite例子中的last參數(shù)值改成break,代碼如下:

          location /view {
           echo " view : $uri ";
           }
          location /download_break/ {
           rewrite ^/download_break/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 break;
           rewrite ^/download_break/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb break;
           echo " download_break new uri : $uri ";
          }

          在瀏覽器中請求http://crazydemo.com/download_break/1/video/10,地址發(fā)生了重寫,但是location并沒有跳轉(zhuǎn),而是直接結(jié)束了,結(jié)果如圖7-18所示。

          圖7-18 顯示結(jié)果

          在location上下文中,last和break是有區(qū)別的:last其實就相當(dāng)于一個新的URL,Nginx進行了一次新的location匹配,通過last獲得一個可以轉(zhuǎn)到其他location配置中處理的機會(內(nèi)部的重定向);而break在一個location中將原來的URL(包括URI和args)改寫之后,再繼續(xù)進行后面的處理,這個重寫之后的請求始終都是在同一個location上下文中,并沒有發(fā)生內(nèi)部跳轉(zhuǎn)。

          這里要注意:last和break的區(qū)別僅僅發(fā)生在location上下文中;如果發(fā)生在server上下文,那么last和break的作用是一樣的。

          還要注意:在location上下文中的rewrite指令使用last指令參數(shù)會再次以新的URI重新發(fā)起內(nèi)部重定向,再次進行l(wèi)ocation匹配,而新的URI極有可能和舊的URI一樣再次匹配到相同的目標(biāo)location中,這樣死循環(huán)就發(fā)生了。當(dāng)循環(huán)到第10次時,Nginx會終止這樣無意義的循環(huán)并返回500錯誤。這一點需要特別注意。

          如果rewrite指令使用的flag參數(shù)的值是permanent,就表示進行外部重定向,也就是在客戶端進行重定向。此時,服務(wù)器將新URI地址返回給客戶端瀏覽器,并且返回301(永久重定向的響應(yīng)碼)給客戶端。客戶端將使用新的重定向地址再發(fā)起一次遠程請求。

          永久重定向permanent的使用示例如下:

           #rewrite指令permanent參數(shù)演示
           location /download_permanent/ {
           rewrite ^/download_permanent/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 permanent;
           rewrite ^/download_permanent/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb permanent; return 404;
          }

          在瀏覽器中請求http://crazydemo.com/download_permanent/1/video/10,輸出的結(jié)果如圖7-19所示。

          圖7-19 輸出的結(jié)果

          從以上結(jié)果可以看出,永久重定向有兩個比較大的特點:

          (1)瀏覽器的地址欄地址變成了重定向地址

          http://crazydemo.com/view/1/mp3/10.mp3。

          (2)從Fiddler抓包工具可以看到,第一個請求地址的響應(yīng)狀態(tài)碼為301,如圖7-20所示。

          圖7-20 永久重定向的響應(yīng)碼示意圖

          外部重定向與內(nèi)部重定向是有本質(zhì)區(qū)別的。從數(shù)量上說,外部重定向有兩次請求,內(nèi)部重定向只有一次請求。通過上面的幾個示例,大家應(yīng)該體會得相當(dāng)深刻了。

          如果rewrite指令使用的flag參數(shù)的值是redirect,就表示進行外部重定向,表現(xiàn)的行為與permanent參數(shù)值完全一樣,不同的是返回302(臨時重定向的響應(yīng)碼)給客戶端。

          有關(guān)redirect參數(shù)值的實例這里不進行演示,大家可自行下載和運行本文的源碼并細細體會。

          rewrite能夠利用正則捕獲組設(shè)置變量,作為實驗,我們可以在Nginx的配置文件中加入這么一條location規(guī)則:

          location /capture_demo {
           rewrite ^/capture_demo/(.*)/video/(.*)$ /view/$1/mp3/$2.mp3 break;
           rewrite ^/capture_demo/(.*)/audio/(.*)*$ /view/$1/mp3/$2.rmvb break;
          捕獲組
          捕獲組 echo " 捕獲組1:$1;捕獲組2:$2";
          }

          在瀏覽器中請求http://crazydemo.com/capture_demo/group1/video/group2,輸出的結(jié)果如圖7-21所示。

          圖7-21 輸出的結(jié)果

          if條件指令

          if條件指令配置項的格式如下:

          if (condition) {...}

          當(dāng)if條件滿足時,執(zhí)行配置塊中的配置指令。if的配置塊相當(dāng)于引入了一個新的上下文作用域。if條件指令適用于server和location兩個上下文。

          condition條件表達式可以用到一系列比較操作符,大致如下:

          (1)==:相等。

          (2)!=:不相等。

          (3)~:區(qū)分字母大小寫模式匹配。

          (4)~*:不區(qū)分字母大小寫模式匹配。

          (5)還有其他幾個專用比較符號,比如判斷文件及目錄是否存在的符號,等等。

          下面是一個簡單的演示程序,根據(jù)內(nèi)置變量$http_user_agent的值判斷客戶端的類型,代碼如下:

          #if指令的演示程序
          location /if_demo {
           if ($http_user_agent ~*"Firefox") { #匹配Firefox瀏覽器
           return 403;
           }

          匹配谷歌瀏覽器

           if ($http_user_agent ~*"Chrome") { #匹配Chrome谷歌瀏覽器
           return 301;
           }
           if ($http_user_agent ~*"iphone") { #匹配iPhone手機
           return 302;
           }
           if ($http_user_agent ~*"android") { #匹配安卓手機
           return 404;
           }
           return 405; #其他瀏覽器默認訪問規(guī)則
          }

          在火狐瀏覽器中訪問http://crazydemo.com/if_demo,結(jié)果如圖7-22所示。

          圖7-22 火狐瀏覽器的訪問結(jié)果

          在谷歌瀏覽器中訪問http://crazydemo.com/if_demo,結(jié)果如圖7-23所示。

          圖7-23 谷歌瀏覽器的訪問結(jié)果

          在演示代碼中使用到了return指令,用于返回HTTP的狀態(tài)碼。

          return指令會停止同一個作用域的剩余指令處理,并返回給客戶端指定的響應(yīng)碼。

          return指令可以用于server、location、if上下文中,執(zhí)行階段是rewrite階段。其指令的格式如下:

          #格式一:返回響應(yīng)的狀態(tài)碼和提示文字,提示文字可選
          return code [text];
          #格式二:返回響應(yīng)的重定向狀態(tài)碼(如301)和重定向URL
          return code URL;
          #格式三:返回響應(yīng)的重定向URL,默認的返回狀態(tài)碼是臨時重定向302
          return URL;

          add_header指令

          response header一般是以key:value的形式,例如Content-Encoding:

          gzip、Cache-Control:no-store,設(shè)置的命令如下:

          add_header Cache-Control no-store
          add_header Content-Encoding gzip

          但是,有一個十分常用的response header為Content-Type,可以在它設(shè)置了類型的同時指定charset,例如text/html;charset=utf-8,由于其存在分號,而分號在配置文件中作為結(jié)束符,因此在配置時需要用引號把其引起來,配置如下:

          add_header Content-Type 'text/html; charset=utf-8';

          另外,由于沒有單獨設(shè)置charset的key,因此要設(shè)置響應(yīng)的charset就需要使用Content-Type來指定charset。

          使用AJAX進行跨域請求時,瀏覽器會向跨域資源的服務(wù)端發(fā)送一個OPTIONS請求,用于判斷實際請求是否安全或者判斷服務(wù)端是否允許跨域訪問,這種請求也叫作預(yù)檢請求。跨域訪問的預(yù)檢請求是瀏覽器自動發(fā)出的,用戶程序往往不知情,如果不進行特別的配置,那么客戶端發(fā)出一次請求,在服務(wù)端往往會收到兩個請求;一個是預(yù)檢請求;另一個是正式的請求。后端的服務(wù)器(PHP或者Tomcat)如果不經(jīng)過特殊的過濾,那么很容易將OPTIONS預(yù)檢請求當(dāng)成正式的數(shù)據(jù)請求。

          對于客戶端而言,只有預(yù)檢請求返回成功,客戶端才開始正式請求。在實際的使用場景中,預(yù)檢請求比較影響性能,用戶往往會有兩倍請求的感覺,所以一般會在Nginx代理服務(wù)端對預(yù)檢請求進行提前攔截,同時對預(yù)檢請求設(shè)置比較長時間的有效期。

          upstream zuul {
           #server 192.168.233.1:7799;
           server "192.168.233.128:7799";
           keepalive 1000;
           }
           server {
           listen 80;
           server_name nginx.server *.nginx.server;
           default_type 'text/html';
           charset utf-8;
           #轉(zhuǎn)發(fā)到上游服務(wù)器,但是 'OPTIONS' 請求直接返回空
           location / {
           if ($request_method='OPTIONS') {
           add_header Access-Control-Max-Age 1728000;
           add_header Access-Control-Allow-Origin *;
           add_header Access-Control-Allow-Credentials true;
           add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
           add_header Access-Control-Allow-Headers 'Keep-Alive,User-Agent,X-Requested-With,\
          If-Modified-Since,Cache-Control,Content-Type,token';
           return 204;
           }
           proxy_pass http://zuul/ ;
           }
           }

          配置Nginx,加入Access-Control-Max-Age請求頭,用來指定本次預(yù)檢請求的有效期,單位為秒。上面結(jié)果中的有效期是20天(1 728 000秒),即允許緩存該條回應(yīng)1 728 000秒,在此期間客戶端不用發(fā)出另一條預(yù)檢請求。

          指令的執(zhí)行順序

          大多數(shù)Nginx新手都會頻繁遇到這樣一個困惑:當(dāng)同一個location配置塊使用了多個Nginx模塊的配置指令時,這些指令的執(zhí)行順序很可能會跟它們的書寫順序大相徑庭。現(xiàn)在就來看這樣一個令人困惑的例子:

          location /sequence_demo_1 {
           set $a foo;
           echo $a;
           set $a bar;
           echo $a;
          }

          上面的代碼先給變量$a賦值foo,隨后輸出,再給變量$a賦值bar,隨后輸出。如果這是一段Java代碼,毫無疑問,最終的輸出結(jié)果一定為“foo bar”。然而不幸的是,事實并非如此,在瀏覽器中訪問http://crazydemo.com/sequence_demo_1,結(jié)果如圖7-24所示。

          圖7-24 輸出的結(jié)果

          為什么出現(xiàn)了這種不合常理的現(xiàn)象呢?

          前面講到,Nginx的請求處理階段共有11個,分別是post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content以及l(fā)og。其中3個比較常見的按照執(zhí)行時的先后順序依次是rewrite階段、access階段以及content階段。

          Nginx的配置指令一般只會注冊并運行在其中的某一個處理階段,比如set指令就是在rewrite階段運行的,而echo指令只會在content階段運行。在一次請求處理流程中,rewrite階段總是在content階段之前執(zhí)行。因此,屬于rewrite階段的配置指令(示例中的set)總是會無條件地在content階段的配置指令(示例中的echo)之前執(zhí)行,即便是echo配置項出現(xiàn)在set配置項的前面。

          上面例子中的指令按照請求處理階段的先后次序排序,實際的執(zhí)行次序如下:

          location /sequence_demo_1 {
           #rewrite階段的配置指令,執(zhí)行在前面
           set $a foo;
           set $a bar;
           #content階段的配置指令,執(zhí)行在后面
           echo $a;
           echo $a;
          }

          所以,輸出的結(jié)果就是bar bar了。

          本文給大家講解的內(nèi)容是Nginx/OpenResty詳解,Nginx的rewrite模塊指令

          1. 下篇文章給大家講解的是 Nginx/OpenResty詳解,反向代理與負載均衡配置;
          2. 覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
          3. 感謝大家的支持!

          主站蜘蛛池模板: 国产裸体歌舞一区二区| 色噜噜狠狠一区二区三区| 视频一区二区在线观看| 国产精品自在拍一区二区不卡| 久久亚洲色一区二区三区| 精品女同一区二区三区免费站 | 国产三级一区二区三区| 亚洲日韩国产精品第一页一区| 久久精品国产AV一区二区三区| 在线观看国产一区亚洲bd| 亚洲AV本道一区二区三区四区| 国产成人综合精品一区| 激情无码亚洲一区二区三区| 日韩精品无码一区二区三区AV | 一区二区三区视频观看| 亚洲一区二区影视| 三上悠亚一区二区观看| 国产天堂在线一区二区三区 | 日韩免费一区二区三区在线| 国产精品女同一区二区久久| 中文字幕无线码一区二区| 伊人激情AV一区二区三区| 无码日韩人妻AV一区免费l| 在线视频一区二区日韩国产| 无码国产精品一区二区免费式影视| 久久国产精品免费一区二区三区| 一本一道波多野结衣AV一区| 熟女精品视频一区二区三区| 久久婷婷色综合一区二区| 国产精品视频一区| 亚洲AV无码一区二区大桥未久| 91久久精品午夜一区二区| 亚洲电影国产一区| 国产麻豆精品一区二区三区| 精品国产一区二区三区无码| 亚洲欧美日韩中文字幕一区二区三区 | 精品人妻少妇一区二区三区不卡| 中文字幕一区二区三区精彩视频| 久久4k岛国高清一区二区| 国产a∨精品一区二区三区不卡| 精品国产一区二区三区久久|