nginx指令碼引擎與變數設計 二

2021-08-26 12:58:36 字數 3065 閱讀 5236

location /

}(一) set行的解析

1. 我們首先看這裡這句:

為什麼這個函式的第三個引數flag,被設定成ngx_http_var_changeable,那是因為set之後的第乙個的變數可以在乙個if配置裡面出現多次,每次可以改變它的值,當然還有nochangeable的,後面碰到再說。緊接著,把這個變數放到全域性變數陣列中,同時記錄它的所在位置(即下標index),即函式ngx_http_get_variable_index。

2. 通過圖中所示,先處理的是set後面的第二個變數,那第乙個怎麼辦呢?先處理它使用原因的,一會就可以看到了。這個變數通過ngx_http_rewrite_value函式來處理的,在處理時帶有$的變數,nginx裡面稱作「complex value」,於是分配ngx_http_script_complex_value_code_t結構同時使用ngx_http_script_complex_value_code來處理,接下來有幾行**需要注意下:

// lengths和values陣列會在ngx_http_script_compile的執行過程中被填充

sc.lengths = &complex->lengths;

sc.values = &lcf->codes;

// complete_lengths置1,是為了給lengths陣列結尾(以null指標填充),因為在運

// 行這個陣列中的成員時,碰到null時,執行就結束了。

sc.complete_lengths = 1;

3. ngx_http_script_compile函式算是這裡的乙個核心,主要是分離當前「complex value」中的一些不同型別的變數,具體邏輯不難看懂,我們只把一些需要注意的地方強調下就行了。

在開始的時候有個函式叫ngx_http_script_init_arrays,這個函式對flushes,lengths和values三個陣列的初始容量給出了乙個估計值,當然nginx的陣列結構在初始空間不夠的時候會自動擴充的,這個就不用太追究了。

在函式ngx_http_script_add_capture_code中,有個這樣的賦值動作code->n = 2 * n,為什麼是2*n呢?這個跟pcre儲存匹配結果集的結構有關,後面我們會講到。

4. 在處理set 中的第乙個引數的時候,它的handler被置為了ngx_http_script_set_var_code,通過這個函式,我們也就知道了為什麼要先處理後乙個引數:

// e->ip就是之前在解析時設定的各種結構體

// e->sp是通過解析得到的變數處理結果的乙個陣列,變數的放置順序跟

// ip中的順序一致,而且隨著處理而遞增,所以為了保持中處理的一致性(這樣

// 就可以保證許多地方使用一致的處理方式)。這裡sp—就可以得到之前的處

// 理值,得到我們想要的結果了。

e->sp--;

r->variables[code->index].len = e->sp->len;

r->variables[code->index].valid = 1;

r->variables[code->index].no_cacheable = 0;

r->variables[code->index].not_found = 0;

r->variables[code->index].data = e->sp->data;

(二) rewrite行的解析

有了前面對if和set的介紹,rewrite分析起來就簡單多了,大多數的處理前面都已經出現過了,這裡只說幾個重點。

1. 在rewrite後面第二個引數中,凡是以「http://」,「https://」,「$scheme」,或者是最後的引數是「redirect」的,在後續的處理都是產生302的響應,其次最後的引數裡,如「permanent」會產生301響應,last和break將會產生nginx內部的重定向(相當於重新做一次http的請求),會重新進行location的匹配等,但是它們的區別在於break在重定向時,就不會在做重定向的處理,而last將會繼續。

2. 對於rewrite後面第二個引數的處理,跟處理set中第二個變數的過程是大致一樣的。需要強調的有以下幾點:

// 剛開始的時候已經給regex做了初始化,為什麼後面有重新賦值了一次呢?原因就是「它可能變了」。。。

對於上面這個問題,可以追溯到ngx_http_script_add_code函式,我們知道nginx在對陣列push時,如果發現空間不足會做擴充,在擴充時會分配原來兩倍大小的空間,並把原有資料copy過來。這樣一樣原來執行這個陣列中的一些指標值此時就不能再用了,而要指向他們的「新家」,這也就是這裡regex重新賦值以及以®ex為引數傳遞給ngx_http_script_add_code的目的所在。

3. 到這裡我們的if指令到了結束的時候,那麼就以乙個null來做結尾。

if (last)

*code = null;

}看最後這一句:

regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - (u_char *) regex;

這裡其實說明了當前位置距離codes陣列的大小,這樣在必要的時候,例如e->ip += code->next,跳過當前結構去處理下乙個,很方便。

到這裡,基本的輪廓就是這樣子,至於各個handler的執行細節,大家可以自己去閱讀**,提示一點的是,要結合e->ip,e->sp等,ngx_http_script_engine_t結構中的一些成員來看,就容易懂了。

nginx指令碼引擎與設計設計 三

這一部分我們將 一些較細節的東西,加上前面 一 二 兩篇文章對典型情景的分析,我相信應該會對大家理解nginx的指令碼解析機制有很大的幫助的。這裡我們關注ngx http core main conf t 下面簡寫為cmcf 結構中的這兩個成員,cmcf variables keys和cmcf va...

引擎學習之二 設計引擎

1 建立動態和靜態鏈結庫 lib hinstance loadlibrary lpctstr plibfilename zfxrenderer.cpp zfxrenderer.h 建立,得到,釋放 zfxrenderdevice.h 用於定義介面 確保載入到記憶體中的dll只載入一次,如果另乙個應用...

再談nginx變數 二

nginx中除了一些內建變數,自定義變數 通過set指令定義的 還有一模擬較特別的變數,我稱它們為特殊字首變數,這類變數多數在 內建變數陣列內是找不到的,形式可以分一下幾類 其中有些常見的http 和sent http 其實主要是一些header 在內建變數陣列中已經給出,多數偏僻的則沒有指明,所以...