<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Nginx 變量漫談(六)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    Nginx 內建變量用在“子請求”的上下文中時,其行為也會變得有些微妙。

     

        前面在 (三) 中我們已經知道,許多內建變量都不是簡單的“存放值的容器”,它們一般會通過注冊“存取處理程序”來表現得與眾不同,而它們即使有存放值的容器,也只是用于緩存“存取處理程序”的計算結果。我們之前討論過的 $args 變量正是通過它的“取處理程序”來返回當前請求的 URL 參數串。因為當前請求也可以是“子請求”,所以在“子請求”中讀取 $args,其“取處理程序”會很自然地返回當前“子請求”的參數串。我們來看這樣的一個例子:

        location /main {
            echo "main args: $args";
            echo_location /sub "a=1&b=2";
        }
     
        location /sub {
            echo "sub args: $args";
        }

    這里在 /main 接口中,先用 echo 指令輸出當前請求的 $args 變量的值,接著再用 echo_location 指令發起子請求 /sub. 這里值得注意的是,我們在 echo_location 語句中除了通過第一個參數指定“子請求”的 URI 之外,還提供了第二個參數,用以指定該“子請求”的 URL 參數串(即 a=1&b=2)。最后我們定義了 /sub 接口,在里面輸出了一下 $args 的值。請求 /main 接口的結果如下:

        $ curl 'http://localhost:8080/main?c=3'
        main args: c=3
        sub args: a=1&b=2

    顯然,當 $args 用在“主請求” /main 中時,輸出的就是“主請求”的 URL 參數串,c=3;而當用在“子請求” /sub 中時,輸出的則是“子請求”的參數串,a=1&b=2。這種行為正符合我們的直覺。

     

        與 $args 類似,內建變量 $uri 用在“子請求”中時,其“取處理程序”也會正確返回當前“子請求”解析過的 URI:

        location /main {
            echo "main uri: $uri";
            echo_location /sub;
        }
     
        location /sub {
            echo "sub uri: $uri";
        }

    請求 /main 的結果是

        $ curl 'http://localhost:8080/main'
        main uri: /main
        sub uri: /sub

    這依然是我們所期望的。

     

        但不幸的是,并非所有的內建變量都作用于當前請求。少數內建變量只作用于“主請求”,比如由標準模塊ngx_http_core 提供的內建變量 $request_method.

     

        變量 $request_method 在讀取時,總是會得到“主請求”的請求方法,比如 GETPOST 之類。我們來測試一下:

        location /main {
            echo "main method: $request_method";
            echo_location /sub;
        }
     
        location /sub {
            echo "sub method: $request_method";
        }

    在這個例子里,/main 和 /sub 接口都會分別輸出 $request_method 的值。同時,我們在 /main 接口里利用echo_location 指令發起一個到 /sub 接口的 GET “子請求”。我們現在利用 curl 命令行工具來發起一個到/main 接口的 POST 請求:

        $ curl --data hello 'http://localhost:8080/main'
        main method: POST
        sub method: POST

    這里我們利用 curl 程序的 --data 選項,指定 hello 作為我們的請求體數據,同時 --data 選項會自動讓發送的請求使用 POST 請求方法。測試結果證明了我們先前的預言,$request_method 變量即使在 GET “子請求” /sub 中使用,得到的值依然是“主請求” /main 的請求方法,POST.

     

        有的讀者可能覺得我們在這里下的結論有些草率,因為上例是先在“主請求”里讀取(并輸出)$request_method 變量,然后才發“子請求”的,所以這些讀者可能認為這并不能排除 $request_method在進入子請求之前就已經把第一次讀到的值給緩存住,從而影響到后續子請求中的輸出結果。不過,這樣的顧慮是多余的,因為我們前面在 (五) 中也特別提到過,緩存所依賴的變量的值容器,是與當前請求綁定的,而由ngx_echo 模塊發起的“子請求”都禁用了父子請求之間的變量共享,所以在上例中,$request_method 內建變量即使真的使用了值容器作為緩存(事實上它也沒有),它也不可能影響到 /sub 子請求。

     

        為了進一步消除這部分讀者的疑慮,我們不妨稍微修改一下剛才那個例子,將 /main 接口輸出$request_method 變量的時間推遲到“子請求”執行完畢之后:

        location /main {
            echo_location /sub;
            echo "main method: $request_method";
        }
     
        location /sub {
            echo "sub method: $request_method";
        }

    讓我們重新測試一下:

        $ curl --data hello 'http://localhost:8080/main'
        sub method: POST
        main method: POST

    可以看到,再次以 POST 方法請求 /main 接口的結果與原先那個例子完全一致,除了父子請求的輸出順序顛倒了過來(因為我們在本例中交換了 /main 接口中那兩條輸出配置指令的先后次序)。

     

        由此可見,我們并不能通過標準的 $request_method 變量取得“子請求”的請求方法。為了達到我們最初的目的,我們需要求助于第三方模塊 ngx_echo 提供的內建變量 $echo_request_method

        location /main {
            echo "main method: $echo_request_method";
            echo_location /sub;
        }
     
        location /sub {
            echo "sub method: $echo_request_method";
        }

    此時的輸出終于是我們想要的了:

        $ curl --data hello 'http://localhost:8080/main'
        main method: POST
        sub method: GET

    我們看到,父子請求分別輸出了它們各自不同的請求方法,POST 和 GET.

     

        類似 $request_method,內建變量 $request_uri 一般也返回的是“主請求”未經解析過的 URL,畢竟“子請求”都是在 Nginx 內部發起的,并不存在所謂的“未解析的”原始形式。

     

        如果真如前面那部分讀者所擔心的,內建變量的值緩存在共享變量的父子請求之間起了作用,這無疑是災難性的。我們前面在 (五) 中已經看到 ngx_auth_request 模塊發起的“子請求”是與其“父請求”共享一套變量的。下面是一個這樣的可怕例子:

        map $uri $tag {
            default     0;
            /main       1;
            /sub        2;
        }
     
        server {
            listen 8080;
     
            location /main {
                auth_request /sub;
                echo "main tag: $tag";
            }
     
            location /sub {
                echo "sub tag: $tag";
            }
        }

    這里我們使用久違了的 map 指令來把內建變量 $uri 的值映射到用戶變量 $tag 上。當 $uri 的值為 /main時,則賦予 $tag 值 1,當 $uri 取值 /sub 時,則賦予 $tag 值 2,其他情況都賦 0. 接著,我們在 /main接口中先用 ngx_auth_request 模塊的 auth_request 指令發起到 /sub 接口的子請求,然后再輸出變量 $tag的值。而在 /sub 接口中,我們直接輸出變量 $tag. 猜猜看,如果我們訪問接口 /main,將會得到什么樣的輸出呢?

        $ curl 'http://localhost:8080/main'
        main tag: 2

    咦?我們不是分明把 /main 這個值映射到 1 上的么?為什么實際輸出的是 /sub 映射的結果 2 呢?

     

        其實道理很簡單,因為我們的 $tag 變量在“子請求” /sub 中首先被讀取,于是在那里計算出了值 2(因為 $uri 在那里取值 /sub,而根據 map 映射規則,$tag 應當取值 2),從此就被 $tag 的值容器給緩存住了。而 auth_request 發起的“子請求”又是與“父請求”共享一套變量的,于是當 Nginx 的執行流回到“父請求”輸出 $tag 變量的值時,Nginx 就直接返回緩存住的結果 2 了。這樣的結果確實太意外了。

     

        從這個例子我們再次看到,父子請求間的變量共享,實在不是一個好主意。

     

        (未完待續)

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全