文章目錄
- 模塊配置結構
- 模塊配置指令
- 先看一下 ngx_command_t 結構
- 一個模塊配置的demo
- 簡單模塊配置的案例演示
- 模塊上下文結構
- 模塊的定義
模塊配置結構
Nginx中每個模塊都會提供一些指令,以便于用戶通過配置去控制該模塊的行為。
Nginx的配置信息分成了幾個作用域(scope,有時也稱作上下文)。作用域有main, server, 以及location。
模塊配置指令
先看一下 ngx_command_t 結構
位置: src/core 目錄下 ngx_conf_file.h
ngx_command_t原型:
typedef struct ngx_command_s ngx_command_t;
struct ngx_command_s {ngx_str_t name; // 配置指令名稱ngx_uint_t type; // 該配置的類型,其實更準確一點說,是該配置指令屬性的集合。(具體見下文)char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // (具體見下文)ngx_uint_t conf; /*該字段被NGX_HTTP_MODULE類型模塊所用 (我們編寫的基本上都是NGX_HTTP_MOUDLE,只有一些nginx核心模塊是非NGX_HTTP_MODULE),該字段指定當前配置項存儲的內存位置。實際上是使用哪個內存池的問題。因為http模塊對所要保存的配置信息,劃分了main, server和location三個地方進行存儲,每個地方都有一個內存池用來分配存儲這些信息的內存。這里可能的值為 NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET。當然也可以直接置為0,就是NGX_HTTP_MAIN_CONF_OFFSET。*/ngx_uint_t offset; /*指定該配置項值的精確存放位置,一般指定為某一個結構體變量的字段偏移。因為對于配置信息的存儲,一般我們都是定義個結構體來存儲的。那么比如我們定義了一個結構體A,該項配置的值需要存儲到該結構體的b字段。那么在這里就可以填寫為offsetof(A, b)。對于有些配置項,它的值不需要保存或者是需要保存到更為復雜的結構中時,這里可以設置為0。*/void *post; /* 該字段存儲一個指針。可以指向任何一個在讀取配置過程中需要的數據,以便于進行配置讀取的處理。大多數時候,都不需要,所以簡單地設為0即可。*/
};
補充說明:
1)對type字段
nginx提供了很多預定義的屬性值(一些宏定義),通過邏輯或運算符可組合在一起,形成對這個配置指令的詳細的說明。
屬性值可以有:
NGX_CONF_NOARGS:配置指令不接受任何參數。
NGX_CONF_TAKE1:配置指令接受1個參數。
NGX_CONF_TAKE2:配置指令接受2個參數。
NGX_CONF_TAKE3:配置指令接受3個參數。
NGX_CONF_TAKE4:配置指令接受4個參數。
NGX_CONF_TAKE5:配置指令接受5個參數。
NGX_CONF_TAKE6:配置指令接受6個參數。
NGX_CONF_TAKE7:配置指令接受7個參數。
可以組合多個屬性,比如一個指令即可以不填參數,也可以接受1個或者2個參數。那么就是
NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。
nginx還提供了一些定義,使用起來更簡潔:
NGX_CONF_TAKE12:配置指令接受1個或者2個參數。
NGX_CONF_TAKE13:配置指令接受1個或者3個參數。
NGX_CONF_TAKE23:配置指令接受2個或者3個參數。
NGX_CONF_TAKE123:配置指令接受1個或者2個或者3參數。
NGX_CONF_TAKE1234:配置指令接受1個或者2個或者3個或者4個參數。
NGX_CONF_1MORE:配置指令接受至少一個參數。
NGX_CONF_2MORE:配置指令接受至少兩個參數。
NGX_CONF_MULTI:配置指令可以接受多個參數,即個數不定。
NGX_CONF_BLOCK:配置指令可以接受的值是一個配置信息塊。也就是一對大括號括起來的內容。里面可以再包括很多的配置指令。比如常見的server指令就是這個屬性的。
NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”,最終會被轉成bool值。
NGX_CONF_ANY:配置指令可以接受的任意的參數值。一個或者多個,或者”on”或者”off”,或者是配置塊。
需要說明的是,無論如何,nginx的配置指令的參數個數不可以超過NGX_CONF_MAX_ARGS個。目前這個值被定義為8,也就是不能超過8個參數值。
下面介紹一組說明配置指令作用域的相關屬性:
NGX_DIRECT_CONF:可以出現在配置文件中最外層。例如已經提供的配置指令daemon,master_process等。
NGX_MAIN_CONF:http、mail、events、error_log等。
NGX_ANY_CONF:該配置指令可以出現在任意配置級別上。
對于我們編寫的大多數模塊而言,都是在處理http相關的事情,也就是所謂的都是NGX_HTTP_MODULE,對于這樣類型的模塊,其配置可能出現的位置也是分為直接出現在http里面,以及其他位置:
NGX_HTTP_MAIN_CONF: 可以直接出現在http配置指令里。
NGX_HTTP_SRV_CONF:可以出現在http里面的server配置指令里。
NGX_HTTP_LOC_CONF:可以出現在http server塊里面的location配置指令里。
NGX_HTTP_UPS_CONF:可以出現在http里面的upstream配置指令里。
NGX_HTTP_SIF_CONF:可以出現在http里面的server配置指令里的if語句所在的block中。
NGX_HTTP_LMT_CONF:可以出現在http里面的limit_except指令的block中。
NGX_HTTP_LIF_CONF:可以出現在http server塊里面的location配置指令里的if語句所在的block中。
2)對set字段
這是一個函數指針,當nginx在解析配置的時候,如果遇到這個配置指令,將會把讀取到的值傳遞給這個函數進行分解處理。因為具體每個配置指令的值如何處理,只有定義這個配置指令的人是最清楚的。
函數原型:
// 處理成功時,返回NGX_OK,否則返回NGX_CONF_ERROR或者是一個自定義的錯誤信息的字符串。
/* cf: 該參數里面保存從配置文件讀取到的原始字符串以及相關的一些信息。特別注意的是這個參數的args字段是一個ngx_str_t
類型的數組,該數組的首個元素是這個配置指令本身,第二個元素是指令的第一個參數,第三個元素是第二個參數,依次類推。*/
/* cmd: 這個配置指令對應的ngx_command_t結構。*/
/* conf: 就是定義的存儲這個配置值的結構體,用戶在處理的時候可以使用類型轉換,轉換成自己知道的類型,再進行字段的賦值。*/
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
為了更加方便的實現對配置指令參數的讀取,nginx已經默認提供了對一些標準類型的參數進行讀取的函數,可以直接賦值給set字段使用。
下面列出這些已經實現的set類型函數:
ngx_conf_set_flag_slot:讀取NGX_CONF_FLAG類型的參數。
ngx_conf_set_str_slot:讀取字符串類型的參數。
ngx_conf_set_str_array_slot:讀取字符串數組類型的參數。
ngx_conf_set_keyval_slot:讀取鍵值對類型的參數。
ngx_conf_set_num_slot:讀取整數類型(有符號整數ngx_int_t)的參數。
ngx_conf_set_size_slot:讀取size_t類型的參數,也就是無符號數。
ngx_conf_set_off_slot:讀取off_t類型的參數。
ngx_conf_set_msec_slot: 讀取毫秒值類型的參數。
ngx_conf_set_sec_slot:讀取秒值類型的參數。
ngx_conf_set_bufs_slot:讀取的參數值是2個,一個是buf的個數,一個是buf的大小。例如: output_buffers 1 128k;
ngx_conf_set_enum_slot:讀取枚舉類型的參數,將其轉換成整數ngx_uint_t類型。
ngx_conf_set_bitmask_slot:讀取參數的值,并將這些參數的值以bit位的形式存儲。例如:HttpDavModule模塊的dav_methods指令。
一個模塊配置的demo
static ngx_command_t ngx_http_hello_commands[] = {{ngx_string("hello_string"),NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,ngx_http_hello_string,NGX_HTTP_LOC_CONF_OFFSET,offsetof(ngx_http_hello_loc_conf_t, hello_string),NULL },ngx_null_command // 每個模塊配置后必不可少的 // 它的原型是 #define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }
};
我們定義的配置指令,一個叫hello_string可以接收一個或零個參數,可以出現在http server塊里面的location配置指令里。該配置的處理函數是ngx_http_hello_string。該配置作用域在NGX_HTTP_LOC_CONF_OFFSET(location中)。該配置信息保存在自定義結構體ngx_http_hello_loc_conf_t 的hello_string字段。
簡單模塊配置的案例演示
-
首先我們在src/core/nginx.c文件中找到ngx_core_commands數組。
-
在該數組中添加一條自定義配置。
-
實現處理函數ngx_conf_my_handler(這個函數名是自己起的)。
-
重新編譯install。
-
在nginx.conf配置文件中加上自定義的配置。
-
測試:./nginx -t
模塊上下文結構
這是一個ngx_http_module_t類型的靜態變量。這個變量實際上是提供一組回調函數指針,這些函數有在創建存儲配置信息的對象的函數,也有在創建前和創建后會調用的函數。
ngx_http_module_t結構原型:
typedef struct {ngx_int_t (*preconfiguration)(ngx_conf_t *cf); // 在創建和讀取該模塊的配置信息之前被調用。ngx_int_t (*postconfiguration)(ngx_conf_t *cf); // 在創建和讀取該模塊的配置信息之后被調用。void *(*create_main_conf)(ngx_conf_t *cf); /* 調用該函數創建本模塊位于http block的配置信息存儲結構。該函數成功的時候,返回創建的配置對象。失敗的話,返回NULL。*/char *(*init_main_conf)(ngx_conf_t *cf, void *conf); /* 調用該函數初始化本模塊位于http block的配置信息存儲結構。該函數成功的時候,返回NGX_CONF_OK。失敗的話,返回NGX_CONF_ERROR或錯誤字符串。*/void *(*create_srv_conf)(ngx_conf_t *cf); /* 調用該函數創建本模塊位于http server block的配置信息存儲結構,每個server block會創建一個。該函數成功的時候,返回創建的配置對象。失敗的話,返回NULL。*/char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); /* 因為有些配置指令既可以出現在http block,也可以出現在http server block中。那么遇到這種情況,每個server都會有自己存儲結構來存儲該server的配置,但是在這種情況下http block中的配置與server block中的配置信息發生沖突的時候,就需要調用此函數進行合并,該函數并非必須提供,當預計到絕對不會發生需要合并的情況的時候,就無需提供。當然為了安全起見還是建議提供。該函數執行成功的時候,返回NGX_CONF_OK。失敗的話,返回NGX_CONF_ERROR或錯誤字符串。*/void *(*create_loc_conf)(ngx_conf_t *cf); /* 調用該函數創建本模塊位于location block的配置信息存儲結構。每個在配置中指明的location創建一個。該函數執行成功,返回創建的配置對象。失敗的話,返回NULL。*/char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); /* 與merge_srv_conf類似,這個也是進行配置值合并的地方。該函數成功的時候,返回NGX_CONF_OK。失敗的話,返回NGX_CONF_ERROR或錯誤字符串。*/
} ngx_http_module_t;
Nginx里面的配置信息都是上下一層層的嵌套的,對于具體某個location的話,對于同一個配置,如果當前層次沒有定義,那
么就使用上層的配置,否則使用當前層次的配置。
這些配置信息一般默認都應該設為一個未初始化的值,針對這個需求,Nginx定義了一系列的宏定義來代表各種配置所對應
數據類型的未初始化值,如下:
#define NGX_CONF_UNSET -1
#define NGX_CONF_UNSET_UINT (ngx_uint_t) -1
#define NGX_CONF_UNSET_PTR (void *) -1
#define NGX_CONF_UNSET_SIZE (size_t) -1
#define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1
模塊的定義
對于開發一個模塊來說,我們都需要定義一個ngx_module_t類型的變量來說明這個模塊本身的信息,從某種意義上來說,這是這個模塊最重要的一個信息,它告訴了nginx這個模塊的一些信息,上面定義的配置信息,還有模塊上下文信息,都是通過這個結構來告訴nginx系統的,也就是加載模塊的上層代碼,都需要通過定義的這個結構,來獲取這些信息。
ngx_module_t 原型:
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {ngx_uint_t ctx_index;ngx_uint_t index;char *name;ngx_uint_t spare0;ngx_uint_t spare1;ngx_uint_t version;const char *signature;void *ctx;ngx_command_t *commands;ngx_uint_t type;ngx_int_t (*init_master)(ngx_log_t *log);ngx_int_t (*init_module)(ngx_cycle_t *cycle);ngx_int_t (*init_process)(ngx_cycle_t *cycle);ngx_int_t (*init_thread)(ngx_cycle_t *cycle);void (*exit_thread)(ngx_cycle_t *cycle);void (*exit_process)(ngx_cycle_t *cycle);void (*exit_master)(ngx_cycle_t *cycle);uintptr_t spare_hook0;uintptr_t spare_hook1;uintptr_t spare_hook2;uintptr_t spare_hook3;uintptr_t spare_hook4;uintptr_t spare_hook5;uintptr_t spare_hook6;uintptr_t spare_hook7;
};
模塊可以提供一些回調函數給nginx,當nginx在創建進程線程或者結束進程線程時進行調用。但大多數模塊在這些時刻并不需要做什么,所以都簡單賦值為NULL。