Stark Wong 的個人開發網站
 


 此頁面:更新於 2019 年 5 月 2 日 12 時 04 分 09 秒,頁面處理需時 0.0011 秒
 網站內容版權所有(C)Stark Wong。頁面(不包括檔案)可自由連結。網站系統版本 1.90-AngularJSBase (2015/9/27)
 
網站地圖

Notice: Undefined variable: row in /var/www/html/blog.inc.php on line 22
如何在 NGINX 進行多條件式流程控制

最近我們在加入一個新功能時需要與第三方合作,以識別第三方服務的使用者。然而過程並沒有想像中簡單,而且還涉及多重條件,雖然我們大可以使用 PHP 來處理這個問題,但由於該伺服器本身提供這個功能僅為兼任角色,可免的情況下也不想使用 FCGI,因為始終會消耗比較多系統資源。這裡簡單回顧一下整個過程。

  1. 伺服器回應特定標頭
    最初雙方協議好是第三方網絡在把回應傳給客戶端時會自動植入特定標頭,這樣客戶端程式只需要檢測出特定標頭的存在時就通過識別檢查。對伺服器端來說只需要提供一個特定 URL 就可以。這個在 NGINX 下的特定路徑設定就一句令伺服器提供空白回應:

    return 200 ‘’;

  2. 伺服器回傳特定標頭
    然後我們在 UAT 時發現客戶端並沒有收到特定的標頭,在對方查證後才發現原來他們植入特定標頭是植入到遠端請求而並非回應,這樣我們就需要設定伺服器端回傳特定的標頭 (這裡假設特定標頭為 X-Header1, X-Header2 及 X-Header3):

    add_header X-Header1 $http_x_header1;
    add_header X-Header2 $http_x_header2;
    add_header X-Header3 $http_x_header3;
    return 200 ‘’;

  3. 加入 IP 檢測
    在進行以上修改後再次測試發現,並且所有客戶端均能接收到其中一個標頭,經對方檢測後發現有技術問題導致出現問題,要解決就需要加入客戶端 IP 檢測,我們若檢測到符合 IP 範圍的時候就會取代 X-Header1 令客戶端可通過測試:

    (以下這段必須加到全域設定,也就是說無論是否相關的請求也會進行 IP 區域檢查)
    geo $client_ip $isp_geo {
    default 0;
    xxx.xxx.xxx.0/21 geo;
    yyy.yyy.yyy.0/21 geo;
    zzz.zzz.zzz.0/21 geo;
    255.255.255.255 -1;
    }

    (以下是特定路徑的設定)
    if ($isp_geo = "geo") {
    add_header X-Header1 ip;
    }
  4. if ($isp_geo != "geo") {
    add_header X-Header1 $http_x_header1;
    add_header X-Header2 $http_x_header2;
    add_header X-Header3 $http_x_header3;
    }
    return 200 ‘’;

  5. 需要先傳回特定標頭後才植入 ip
    雖然上列的修改基本上已經能解決偵測的問題,不過我方團隊想知道究竟有多少客戶能通過原來的標頭檢測。上列的修改雖然能解決檢測,但卻不能解決這個新要求,因為基本上會在伺服器端收到特定標頭的請求都必然通過 IP 測試,那樣就根本就不會看到有回傳真正的特定標頭的客戶。這樣的邏輯一般作法只需要用多個 if 條件及/或 if else 就能輕鬆解決。然而 NGINX 的 if 條件式是非常區限性:
    - if 裡面只能檢查單一條件
    - 不支援 else
    - 不支援巢狀式 if (即 if 區域裡面不可以再有 if)

    所以我們需要只用 if = 和 if != 才能解決問題,那就需要創造一個可讓 if 處理的值。既然我們知道 X-Header1, X-Header2 及 X-Header3 的值都可以是空值,那麼我們可以創造一個值來指出是否只有 IP 通過,例如:

    set $result "${http_x_header1}${http_x_header2}${http_x_header3}${isp_geo}";

    這樣,如果 $result 只有 “geo” 的話就代表所有特定標頭都不存在而只有 IP 檢測通過 (即等於 if ($http_x_header1 = ‘’ && $http_x_header2 = ‘’ && $http_x_header3 = ‘’ && $isp_geo = ‘geo’)),那時候我們就可以放心植入 ip 值到 X-Header1了。

    if ($result = "geo") {
    add_header X-Header1 ip;
    }
    if ($result != "geo") {
    add_header X-Header1 $http_x_header1;
    add_header X-Header2 $http_x_header2;
    add_header X-Neader3 $http_x_header3;
    }
    return 200 ‘’;

    這樣修改下,如果客戶有特定標頭,就會回傳特定標頭而不論是否通過 IP 檢測;而如果用戶沒有特定標頭但通過 IP 檢測,就只會回應 ip 作為 X-Header1 的值;而如果客戶兩個條件都不符合,則仍然會回傳特定標頭,但因為特定標頭不存在而不會進行回傳。


撰寫於:2021/12/19 14:21:02 / 回應已關閉
正在讀取回響內容...
其他內容請回到主頁