變量也是nginx的一大亮點,這也使得nginx更加靈活了,變量的語法格式為 $XXX? 或 ${xxxx}
首先說下變量的分類,變量分為內置和自定義,網絡不少對變量的描述都不太準確,他們認為但凡不是nginx原生的變量都是屬于自定義,這么說其實也可以,但嚴格來說,
內置變量應該是但凡編譯到代碼里的都是內置,通用性強
自定義的僅限于配置文件中,局限性小
編譯進代碼的不僅包含ng原生的,也含我們的第三方模塊定義的變量。
自定義的如set $my_var "hello world";
location / {
????add_header My-Var $my_var;
}
內置的都是需要編譯到代碼中的
ng原生變量的就太多了,實現文件在ngx_http_variables.c 和 ngx_stream_variables.c
內置變量需要在代碼里定義,并且調用對應的接口
ngx_http_add_variable 或ngx_stream_add_variable添加到全局中去,內置變量由ng框架進行維護和管理。
變量的抽象定義如下(以下都http為例,stream類同):
struct ngx_http_variable_s {
??? ngx_str_t??? name ;//變量名
??? ngx_http_set_variable_pt set_handler ;//變量的set方法,即寫
? ? ngx_http_get_variable_pt get_handler;//變量的get方法,即讀
??? uintprt_t??????? data ;//調用方法時,傳遞的參數,即變量掛載的任意數據指針,調用get和set的時候會透傳
??? ngx_uint_t flags; //變量標簽特性,NGX_HTTP_VAR_CHANGEABLE ,NGX_HTTP_VAR_NOCACHEABLE
????ngx_uint_t index;//變量的索引值,內置變量都在存儲在一個全局的數組中的,通過下標去讀取變量是最快的,nginx在啟動的時候會初始化
}
?
有了變量,就肯定要涉及到變量的類型。先看
表示變量值的結構體:
typedef ngx_variable_value_t ngx_http_variable_value_t;
typedef struct {
unsigned len:28;
unsigned valid:1;
unsigned no_cacheable:1;
unsigned not_found:1;
unsigned escape:1;
u_char *data;
} ngx_variable_value_t;
?
結構體并未指出變量的類型,其實變量其本質就是一塊內存,nginx無法確定變量的具體類型,于是通過長度確定,由使用者去“強轉”
在c語言內,任何類型 變量其實就是一塊內存,有了內存首地址,還有長度,就夠了。
比如是int類型,對data指向的字符串進行轉整數即可
還是可以二進制的,比如
v->len = sizeof(in_addr_t);
v->data = (u_char *) &sin->sin_addr;
?ng有幾個原生的地址變量就是二進制的。
ngx_http_add_variable 或ngx_stream_add_variable添加到全局中后,任意模塊任何地方都可以使用之。
變量有了,變量主要就是拿來使用的,否則就沒意義,使用最基本肯定是讀,變量存儲了我們想存儲的數據
再看下讀寫方法定義
讀:
typedef ngx_int_t (*ngx_http_get_variable_pt?) (ngx_http_request* r,ngx_http_variable_value_t *v , uintptr_t data) ;
寫:
typedef void (*ngx_http_set_variable_pt?)(ngx_http_request* r,ngx_http_variable_value_t *v , uintptr_t data)
第二個參數就是變量值,需要我們填充該結構體,data則是我們在ngx_http_add_variable時,填充到ngx_http_variable_s 結構體中的data,在某個地方使用了你的變量,那么ng就會調用 你定義好的?get_handler來獲取變量的值
代碼實例:
配置:
server {
?listen 9999;
?location / {
???? proxy_pass ${my_http_url} ;
? }
}
訪問9999端口,ng則會代理到?${my_http_url}存儲的url地址去。
在代碼里 實現get方法
ngx_str_t myurl = ngx_string("127.0.0.1:6666") ;
ngx_int_t? my_get_handler(ngx_http_request* r,ngx_http_variable_value_t *v , uintptr_t data)
{
? ?? v->len =?myurl .len;
???? v->data =?myurl .data ;
? ? ?v->valid = 1 ;//這個必須置1
? ? ?v->not_found=0;//必須置0
? ? v->no_cachebale = 0 ;
?return NGX_OK ;
}
當有人訪問9999端口時,ng就會調用我們定義好的get方法來取這個url地址,該地址ng自己去解析使用,如此可以實現動態的代理,比如可以根據不同的 請求r 來實現不同的代理地址。
ng的變量具體框架實現 其實還是很復雜的,代碼量也是比較大的