基本上作為第三方開(kāi)發(fā)者最可能開(kāi)發(fā)的就是三種類(lèi)型的模塊,即handler,filter和load-balancer嘉抓。
handler模塊
Handler模塊就是接受來(lái)自客戶(hù)端的請(qǐng)求并產(chǎn)生輸出的模塊唾那。配置文件中使用location指令可以配置content handler模塊,當(dāng)Nginx系統(tǒng)啟動(dòng)的時(shí)候垢揩,每個(gè)handler模塊都有一次機(jī)會(huì)把自己關(guān)聯(lián)到對(duì)應(yīng)的location上。如果有多個(gè)handler模塊都關(guān)聯(lián)了同一個(gè)location敛瓷,那么實(shí)際上只有一個(gè)handler模塊真正會(huì)起作用叁巨。當(dāng)然大多數(shù)情況下,模塊開(kāi)發(fā)人員都會(huì)避免出現(xiàn)這種情況琐驴。
handler模塊處理的結(jié)果通常有三種情況: 處理成功俘种,處理失敗(處理的時(shí)候發(fā)生了錯(cuò)誤)或者是拒絕處理秤标。
在拒絕處理的情況下,這個(gè)location的處理就會(huì)由默認(rèn)的handler模塊來(lái)進(jìn)行處理宙刘。例如苍姜,當(dāng)請(qǐng)求一個(gè)靜態(tài)文件的時(shí)候,如果關(guān)聯(lián)到這個(gè)location上的一個(gè)handler模塊拒絕處理悬包,就會(huì)由默認(rèn)的ngx_http_static_module模塊進(jìn)行處理衙猪,該模塊是一個(gè)典型的handler模塊。
模塊配置結(jié)構(gòu)
基本上每個(gè)模塊都會(huì)提供一些配置指令布近,以便于用戶(hù)可以通過(guò)配置來(lái)控制該模塊的行為垫释。
Nginx的配置信息分成了幾個(gè)作用域(scope,有時(shí)也稱(chēng)作上下文),這就是main, server, 以及l(fā)ocation撑瞧。
同樣的每個(gè)模塊提供的配置指令也可以出現(xiàn)在這幾個(gè)作用域里棵譬。那對(duì)于這三個(gè)作用域的配置信息,每個(gè)模塊就需要定義三個(gè)不同的數(shù)據(jù)結(jié)構(gòu)去進(jìn)行存儲(chǔ)预伺。當(dāng)然订咸,不是每個(gè)模塊都會(huì)在這三個(gè)作用域都提供配置指令的。那么也就不一定每個(gè)模塊都需要定義三個(gè)數(shù)據(jù)結(jié)構(gòu)去存儲(chǔ)這些配置信息了酬诀。視模塊的實(shí)現(xiàn)而言脏嚷,需要幾個(gè)就定義幾個(gè)。
對(duì)于模塊配置信息的定義瞒御,命名習(xí)慣是ngx_http_<module name>_(main|srv|loc)_conf_t父叙。這里有個(gè)例子,就是從我們后面將要展示給大家的hello module中截取的肴裙。
<pre>typedef struct
{
ngx_str_t hello_string;
ngx_int_t hello_counter;
}ngx_http_hello_loc_conf_t;</pre>
模塊配置指令
一個(gè)模塊的配置指令是定義在一個(gè)靜態(tài)數(shù)組中的趾唱。同樣地,我們來(lái)看一下從hello module中截取的模塊配置指令的定義践宴。
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_string("hello_counter"),
NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_http_hello_counter,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_loc_conf_t, hello_counter),
NULL },
ngx_null_command
};
其實(shí)看這個(gè)定義鲸匿,就基本能看出來(lái)一些信息。例如阻肩,我們是定義了兩個(gè)配置指令,一個(gè)是叫hello_string运授,可以接受一個(gè)參數(shù)烤惊,或者是沒(méi)有參數(shù)。另外一個(gè)命令是hello_counter吁朦,接受一個(gè)NGX_CONF_FLAG類(lèi)型的參數(shù)柒室。
ngx_command_t的定義,位于src/core/ngx_conf_file.h中逗宜。
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_uint_t offset;
void *post;
};
name: 配置指令的名稱(chēng)雄右。
type: 該配置的類(lèi)型空骚,其實(shí)更準(zhǔn)確一點(diǎn)說(shuō),是該配置指令屬性的集合擂仍。nginx提供了很多預(yù)定義的屬性值(一些宏定義)囤屹,通過(guò)邏輯或運(yùn)算符可組合在一起,形成對(duì)這個(gè)配置指令的詳細(xì)的說(shuō)明逢渔。下面列出可在這里使用的預(yù)定義屬性值及說(shuō)明肋坚。
NGX_CONF_NOARGS:配置指令不接受任何參數(shù)。
NGX_CONF_TAKE1:配置指令接受1個(gè)參數(shù)肃廓。
NGX_CONF_TAKE2:配置指令接受2個(gè)參數(shù)智厌。
NGX_CONF_TAKE3:配置指令接受3個(gè)參數(shù)。
NGX_CONF_TAKE4:配置指令接受4個(gè)參數(shù)盲赊。
NGX_CONF_TAKE5:配置指令接受5個(gè)參數(shù)铣鹏。
NGX_CONF_TAKE6:配置指令接受6個(gè)參數(shù)。
NGX_CONF_TAKE7:配置指令接受7個(gè)參數(shù)哀蘑。
可以組合多個(gè)屬性诚卸,比如一個(gè)指令即可以不填參數(shù),也可以接受1個(gè)或者2個(gè)參數(shù)递礼。nginx提供了一些定義惨险,使用起來(lái)更簡(jiǎn)潔。
NGX_CONF_TAKE12:配置指令接受1個(gè)或者2個(gè)參數(shù)脊髓。
NGX_CONF_TAKE13:配置指令接受1個(gè)或者3個(gè)參數(shù)辫愉。
NGX_CONF_TAKE23:配置指令接受2個(gè)或者3個(gè)參數(shù)。
NGX_CONF_TAKE123:配置指令接受1個(gè)或者2個(gè)或者3參數(shù)将硝。
NGX_CONF_TAKE1234:配置指令接受1個(gè)或者2個(gè)或者3個(gè)或者4個(gè)參數(shù)恭朗。
NGX_CONF_1MORE:配置指令接受至少一個(gè)參數(shù)。
NGX_CONF_2MORE:配置指令接受至少兩個(gè)參數(shù)依疼。
NGX_CONF_MULTI: 配置指令可以接受多個(gè)參數(shù)痰腮,即個(gè)數(shù)不定。
NGX_CONF_BLOCK:配置指令可以接受的值是一個(gè)配置信息塊律罢。也就是一對(duì)大括號(hào)括起來(lái)的內(nèi)容膀值。里面可以再包括很多的配置指令。比如常見(jiàn)的server指令就是這個(gè)屬性的误辑。
NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”沧踏,最終會(huì)被轉(zhuǎn)成bool值。
NGX_CONF_ANY:配置指令可以接受的任意的參數(shù)值巾钉。一個(gè)或者多個(gè)翘狱,或者”on”或者”off”,或者是配置塊砰苍。
最后要說(shuō)明的是潦匈,無(wú)論如何阱高,nginx的配置指令的參數(shù)個(gè)數(shù)不可以超過(guò)NGX_CONF_MAX_ARGS個(gè)。目前這個(gè)值被定義為8茬缩,也就是不能超過(guò)8個(gè)參數(shù)值赤惊。
下面介紹一組說(shuō)明配置指令可以出現(xiàn)的位置的屬性。
NGX_DIRECT_CONF:可以出現(xiàn)在配置文件中最外層寒屯。例如已經(jīng)提供的配置指令daemon荐捻,master_process等。
NGX_MAIN_CONF: http寡夹、mail处面、events、error_log等菩掏。
NGX_ANY_CONF: 該配置指令可以出現(xiàn)在任意配置級(jí)別上魂角。
對(duì)于我們編寫(xiě)的大多數(shù)模塊而言,都是在處理http相關(guān)的事情智绸,也就是所謂的都是NGX_HTTP_MODULE野揪,對(duì)于這樣類(lèi)型的模塊,其配置可能出現(xiàn)的位置也是分為直接出現(xiàn)在http里面瞧栗,以及其他位置斯稳。
NGX_HTTP_MAIN_CONF: 可以直接出現(xiàn)在http配置指令里。
NGX_HTTP_SRV_CONF: 可以出現(xiàn)在http里面的server配置指令里迹恐。
NGX_HTTP_LOC_CONF: 可以出現(xiàn)在http server塊里面的location配置指令里挣惰。
NGX_HTTP_UPS_CONF: 可以出現(xiàn)在http里面的upstream配置指令里。
NGX_HTTP_SIF_CONF: 可以出現(xiàn)在http里面的server配置指令里的if語(yǔ)句所在的block中殴边。
NGX_HTTP_LMT_CONF: 可以出現(xiàn)在http里面的limit_except指令的block中憎茂。
NGX_HTTP_LIF_CONF: 可以出現(xiàn)在http server塊里面的location配置指令里的if語(yǔ)句所在的block中。
set: 這是一個(gè)函數(shù)指針锤岸,當(dāng)nginx在解析配置的時(shí)候竖幔,如果遇到這個(gè)配置指令,將會(huì)把讀取到的值傳遞給這個(gè)函數(shù)進(jìn)行分解處理是偷。因?yàn)榫唧w每個(gè)配置指令的值如何處理拳氢,只有定義這個(gè)配置指令的人是最清楚的。來(lái)看一下這個(gè)函數(shù)指針要求的函數(shù)原型蛋铆。
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
先看該函數(shù)的返回值饿幅,處理成功時(shí),返回NGX_OK戒职,否則返回NGX_CONF_ERROR或者是一個(gè)自定義的錯(cuò)誤信息的字符串。
再看一下這個(gè)函數(shù)被調(diào)用的時(shí)候透乾,傳入的三個(gè)參數(shù)洪燥。
· cf : 該參數(shù)里面保存從配置文件讀取到的原始字符串以及相關(guān)的一些信息磕秤。特別注意的是這個(gè)參數(shù)的args字段是一個(gè)ngx_str_t類(lèi)型的數(shù)組,該數(shù)組的首個(gè)元素是這個(gè)配置指令本身捧韵,第二個(gè)元素是指令的第一個(gè)參數(shù)市咆,第三個(gè)元素是第二個(gè)參數(shù),依次類(lèi)推再来。
· cmd : 這個(gè)配置指令對(duì)應(yīng)的ngx_command_t結(jié)構(gòu)蒙兰。
· conf : 就是定義的存儲(chǔ)這個(gè)配置值的結(jié)構(gòu)體,比如在上面展示的那個(gè)ngx_http_hello_loc_conf_t芒篷。當(dāng)解析這個(gè)hello_string變量的時(shí)候搜变,傳入的conf就指向一個(gè)ngx_http_hello_loc_conf_t類(lèi)型的變量。用戶(hù)在處理的時(shí)候可以使用類(lèi)型轉(zhuǎn)換针炉,轉(zhuǎn)換成自己知道的類(lèi)型挠他,再進(jìn)行字段的賦值。
為了更加方便的實(shí)現(xiàn)對(duì)配置指令參數(shù)的讀取篡帕,nginx已經(jīng)默認(rèn)提供了對(duì)一些標(biāo)準(zhǔn)類(lèi)型的參數(shù)進(jìn)行讀取的函數(shù)殖侵,可以直接賦值給set字段使用。下面來(lái)看一下這些已經(jīng)實(shí)現(xiàn)的set類(lèi)型函數(shù)镰烧。
ngx_conf_set_flag_slot: 讀取NGX_CONF_FLAG類(lèi)型的參數(shù)拢军。
ngx_conf_set_str_slot:讀取字符串類(lèi)型的參數(shù)。
ngx_conf_set_str_array_slot: 讀取字符串?dāng)?shù)組類(lèi)型的參數(shù)怔鳖。
ngx_conf_set_keyval_slot: 讀取鍵值對(duì)類(lèi)型的參數(shù)茉唉。
ngx_conf_set_num_slot: 讀取整數(shù)類(lèi)型(有符號(hào)整數(shù)ngx_int_t)的參數(shù)。
ngx_conf_set_size_slot:讀取size_t類(lèi)型的參數(shù)败砂,也就是無(wú)符號(hào)數(shù)赌渣。
ngx_conf_set_off_slot: 讀取off_t類(lèi)型的參數(shù)。
ngx_conf_set_msec_slot: 讀取毫秒值類(lèi)型的參數(shù)昌犹。
ngx_conf_set_sec_slot: 讀取秒值類(lèi)型的參數(shù)坚芜。
ngx_conf_set_bufs_slot: 讀取的參數(shù)值是2個(gè),一個(gè)是buf的個(gè)數(shù)斜姥,一個(gè)是buf的大小鸿竖。例如: output_buffers 1 128k;
ngx_conf_set_enum_slot: 讀取枚舉類(lèi)型的參數(shù),將其轉(zhuǎn)換成整數(shù)ngx_uint_t類(lèi)型铸敏。
ngx_conf_set_bitmask_slot: 讀取參數(shù)的值缚忧,并將這些參數(shù)的值以bit位的形式存儲(chǔ)。例如:HttpDavModule模塊的dav_methods指令杈笔。
· conf : 該字段被NGX_HTTP_MODULE類(lèi)型模塊所用 (我們編寫(xiě)的基本上都是NGX_HTTP_MOUDLE闪水,只有一些nginx核心模塊是非NGX_HTTP_MODULE),該字段指定當(dāng)前配置項(xiàng)存儲(chǔ)的內(nèi)存位置蒙具。實(shí)際上是使用哪個(gè)內(nèi)存池的問(wèn)題球榆。因?yàn)閔ttp模塊對(duì)所有http模塊所要保存的配置信息朽肥,劃分了main, server和location三個(gè)地方進(jìn)行存儲(chǔ),每個(gè)地方都有一個(gè)內(nèi)存池用來(lái)分配存儲(chǔ)這些信息的內(nèi)存持钉。這里可能的值為 NGX_HTTP_MAIN_CONF_OFFSET衡招、NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET。當(dāng)然也可以直接置為0每强,就是NGX_HTTP_MAIN_CONF_OFFSET始腾。
· offset : 指定該配置項(xiàng)值的精確存放位置,一般指定為某一個(gè)結(jié)構(gòu)體變量的字段偏移空执。因?yàn)閷?duì)于配置信息的存儲(chǔ)浪箭,一般我們都是定義個(gè)結(jié)構(gòu)體來(lái)存儲(chǔ)的。那么比如我們定義了一個(gè)結(jié)構(gòu)體A脆烟,該項(xiàng)配置的值需要存儲(chǔ)到該結(jié)構(gòu)體的b字段山林。那么在這里就可以填寫(xiě)為offsetof(A, b)。對(duì)于有些配置項(xiàng)邢羔,它的值不需要保存或者是需要保存到更為復(fù)雜的結(jié)構(gòu)中時(shí)驼抹,這里可以設(shè)置為0。
· post : 該字段存儲(chǔ)一個(gè)指針拜鹤】蚣剑可以指向任何一個(gè)在讀取配置過(guò)程中需要的數(shù)據(jù),以便于進(jìn)行配置讀取的處理敏簿。大多數(shù)時(shí)候明也,都不需要,所以簡(jiǎn)單地設(shè)為0即可惯裕。
看到這里温数,應(yīng)該就比較清楚了。ngx_http_hello_commands這個(gè)數(shù)組每5個(gè)元素為一組蜻势,用來(lái)描述一個(gè)配置項(xiàng)的所有情況撑刺。那么如果有多個(gè)配置項(xiàng),只要按照需要再增加5個(gè)對(duì)應(yīng)的元素對(duì)新的配置項(xiàng)進(jìn)行說(shuō)明握玛。
模塊的定義
對(duì)于開(kāi)發(fā)一個(gè)模塊來(lái)說(shuō)够傍,我們都需要定義一個(gè)ngx_module_t類(lèi)型的變量來(lái)說(shuō)明這個(gè)模塊本身的信息,從某種意義上來(lái)說(shuō)挠铲,這是這個(gè)模塊最重要的一個(gè)信息冕屯,它告訴了nginx這個(gè)模塊的一些信息,上面定義的配置信息拂苹,還有模塊上下文信息安聘,都是通過(guò)這個(gè)結(jié)構(gòu)來(lái)告訴nginx系統(tǒng)的,也就是加載模塊的上層代碼,都需要通過(guò)定義的這個(gè)結(jié)構(gòu)搞挣,來(lái)獲取這些信息带迟。
ngx_module_t的定義:
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {
ngx_uint_t ctx_index;
ngx_uint_t index;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t abi_compatibility;
ngx_uint_t major_version;
ngx_uint_t minor_version;
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;
};
#define NGX_NUMBER_MAJOR 3
#define NGX_NUMBER_MINOR 1
#define NGX_MODULE_V1 0, 0, 0, 0, \
NGX_DSO_ABI_COMPATIBILITY, NGX_NUMBER_MAJOR, NGX_NUMBER_MINOR
#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
再看一下hello模塊的模塊定義。
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx, /* module context */
ngx_http_hello_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
模塊可以提供一些回調(diào)函數(shù)給nginx囱桨,當(dāng)nginx在創(chuàng)建進(jìn)程線程或者結(jié)束進(jìn)程線程時(shí)進(jìn)行調(diào)用。但大多數(shù)模塊在這些時(shí)刻并不需要做什么嗅绰,所以都簡(jiǎn)單賦值為NULL舍肠。
handler模塊的基本結(jié)構(gòu)
handler模塊必須提供一個(gè)真正的處理函數(shù),這個(gè)函數(shù)負(fù)責(zé)對(duì)來(lái)自客戶(hù)端請(qǐng)求的真正處理窘面。這個(gè)函數(shù)的處理翠语,既可以選擇自己直接生成內(nèi)容,也可以選擇拒絕處理财边,由后續(xù)的handler去進(jìn)行處理肌括,或者是選擇丟給后續(xù)的filter進(jìn)行處理。
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
r是http請(qǐng)求酣难。里面包含請(qǐng)求所有的信息谍夭。 該函數(shù)處理成功返回NGX_OK,處理發(fā)生錯(cuò)誤返回NGX_ERROR憨募,拒絕處理(留給后續(xù)的handler進(jìn)行處理)返回NGX_DECLINE紧索。 返回NGX_OK也就代表給客戶(hù)端的響應(yīng)已經(jīng)生成好了,否則返回NGX_ERROR就發(fā)生錯(cuò)誤了菜谣。
handler模塊的掛載
handler模塊真正的處理函數(shù)通過(guò)兩種方式掛載到處理過(guò)程中珠漂,一種方式就是按處理階段掛載; 另外一種掛載方式就是按需掛載。
按處理階段掛載
為了更精細(xì)地控制對(duì)于客戶(hù)端請(qǐng)求的處理過(guò)程尾膊,nginx把這個(gè)處理過(guò)程劃分成了11個(gè)階段媳危。他們從前到后,依次列舉如下:
NGX_HTTP_POST_READ_PHASE:
讀取請(qǐng)求內(nèi)容階段
NGX_HTTP_SERVER_REWRITE_PHASE:
Server請(qǐng)求地址重寫(xiě)階段
NGX_HTTP_FIND_CONFIG_PHASE:
配置查找階段:
NGX_HTTP_REWRITE_PHASE:
Location請(qǐng)求地址重寫(xiě)階段
NGX_HTTP_POST_REWRITE_PHASE:
請(qǐng)求地址重寫(xiě)提交階段
NGX_HTTP_PREACCESS_PHASE:
訪問(wèn)權(quán)限檢查準(zhǔn)備階段
NGX_HTTP_ACCESS_PHASE:
訪問(wèn)權(quán)限檢查階段
NGX_HTTP_POST_ACCESS_PHASE:
訪問(wèn)權(quán)限檢查提交階段
NGX_HTTP_TRY_FILES_PHASE:
配置項(xiàng)try_files處理階段
NGX_HTTP_CONTENT_PHASE:
內(nèi)容產(chǎn)生階段
NGX_HTTP_LOG_PHASE:
日志模塊處理階段
一般情況下冈敛,我們自定義的模塊待笑,大多數(shù)是掛載在NGX_HTTP_CONTENT_PHASE階段的。掛載的動(dòng)作一般是在模塊上下文調(diào)用的postconfiguration函數(shù)中莺债。
注意:有幾個(gè)階段是特例滋觉,它不調(diào)用掛載地任何的handler,也就是你就不用掛載到這幾個(gè)階段了:
NGX_HTTP_FIND_CONFIG_PHASE
NGX_HTTP_POST_ACCESS_PHASE
NGX_HTTP_POST_REWRITE_PHASE
NGX_HTTP_TRY_FILES_PHASE
所以其實(shí)真正是有7個(gè)phase你可以去掛載handler齐邦。
http static module
本模塊的作用就是讀取磁盤(pán)上的靜態(tài)文件椎侠,并把文件內(nèi)容作為產(chǎn)生的輸出。在Web技術(shù)發(fā)展的早期措拇,只有靜態(tài)頁(yè)面我纪,沒(méi)有服務(wù)端腳本來(lái)動(dòng)態(tài)生成HTML的時(shí)候。恐怕開(kāi)發(fā)個(gè)Web服務(wù)器的時(shí)候浅悉,第一個(gè)要開(kāi)發(fā)就是這樣一個(gè)content handler趟据。
http static module的代碼位于src/http/modules/ngx_http_static_module.c中,總共只有兩百多行近三百行术健⌒诩睿可以說(shuō)是非常短小。
我們首先來(lái)看一下該模塊的模塊上下文的定義荞估。
ngx_http_module_t ngx_http_static_module_ctx = {
NULL, /* preconfiguration */
ngx_http_static_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
連任何與配置相關(guān)的函數(shù)都沒(méi)有咳促。唯一需要調(diào)用的函數(shù)是一個(gè)ngx_http_static_init函數(shù)。
static ngx_int_t
ngx_http_static_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_static_handler;
return NGX_OK;
}
僅僅是掛載這個(gè)handler到NGX_HTTP_CONTENT_PHASE處理階段勘伺。這個(gè)模塊最核心的處理邏輯所在的ngx_http_static_handler函數(shù)跪腹。
過(guò)濾模塊
過(guò)濾(filter)模塊是過(guò)濾響應(yīng)頭和內(nèi)容的模塊,可以對(duì)回復(fù)的頭和內(nèi)容進(jìn)行處理飞醉。它的處理時(shí)間在獲取回復(fù)內(nèi)容之后冲茸,向用戶(hù)發(fā)送響應(yīng)之前。它的處理過(guò)程分為兩個(gè)階段缅帘,過(guò)濾HTTP回復(fù)的頭部和主體轴术,在這兩個(gè)階段可以分別對(duì)頭部和主體進(jìn)行修改。
在代碼中有類(lèi)似的函數(shù):
ngx_http_top_header_filter(r);
ngx_http_top_body_filter(r, in);
就是分別對(duì)頭部和主體進(jìn)行過(guò)濾的函數(shù)股毫。所有模塊的響應(yīng)內(nèi)容要返回給客戶(hù)端膳音,都必須調(diào)用這兩個(gè)接口。
過(guò)濾模塊的調(diào)用是有順序的铃诬,它的順序在編譯的時(shí)候就決定了祭陷。控制編譯的腳本位于auto/modules中趣席,當(dāng)你編譯完Nginx以后兵志,可以在objs目錄下面看到一個(gè)ngx_modules.c的文件。打開(kāi)這個(gè)文件宣肚,有類(lèi)似的代碼:
ngx_module_t *ngx_modules[] = {
...
&ngx_http_write_filter_module,
&ngx_http_header_filter_module,
&ngx_http_chunked_filter_module,
&ngx_http_range_header_filter_module,
&ngx_http_gzip_filter_module,
&ngx_http_postpone_filter_module,
&ngx_http_ssi_filter_module,
&ngx_http_charset_filter_module,
&ngx_http_userid_filter_module,
&ngx_http_headers_filter_module,
&ngx_http_copy_filter_module,
&ngx_http_range_body_filter_module,
&ngx_http_not_modified_filter_module,
NULL
};
從write_filter到not_modified_filter想罕,模塊的執(zhí)行順序是反向的。也就是說(shuō)最早執(zhí)行的是not_modified_filter霉涨,然后各個(gè)模塊依次執(zhí)行按价。所有第三方的模塊只能加入到copy_filter和headers_filter模塊之間執(zhí)行。
nginx的源碼目錄結(jié)構(gòu)
.
├── auto 自動(dòng)檢測(cè)系統(tǒng)環(huán)境以及編譯相關(guān)的腳本
│ ├── cc 關(guān)于編譯器相關(guān)的編譯選項(xiàng)的檢測(cè)腳本
│ ├── lib nginx編譯所需要的一些庫(kù)的檢測(cè)腳本
│ ├── os 與平臺(tái)相關(guān)的一些系統(tǒng)參數(shù)與系統(tǒng)調(diào)用相關(guān)的檢測(cè)
│ └── types 與數(shù)據(jù)類(lèi)型相關(guān)的一些輔助腳本
├── conf 存放默認(rèn)配置文件笙瑟,在make install后楼镐,會(huì)拷貝到安裝目錄中去
├── contrib 存放一些實(shí)用工具,如geo配置生成工具(geo2nginx.pl)
├── html 存放默認(rèn)的網(wǎng)頁(yè)文件往枷,在make install后框产,會(huì)拷貝到安裝目錄中去
├── man nginx的man手冊(cè)
└── src 存放nginx的源代碼
├── core nginx的核心源代碼凄杯,包括常用數(shù)據(jù)結(jié)構(gòu)的定義,以及nginx初始化運(yùn)行的核心代碼如main函數(shù)
├── event 對(duì)系統(tǒng)事件處理機(jī)制的封裝秉宿,以及定時(shí)器的實(shí)現(xiàn)相關(guān)代碼
│ └── modules 不同事件處理方式的模塊化戒突,如select、poll描睦、epoll膊存、kqueue等
├── http nginx作為http服務(wù)器相關(guān)的代碼
│ └── modules 包含http的各種功能模塊
├── mail nginx作為郵件代理服務(wù)器相關(guān)的代碼
├── misc 一些輔助代碼,測(cè)試c++頭的兼容性酌摇,以及對(duì)google_perftools的支持
└── os 主要是對(duì)各種不同體系統(tǒng)結(jié)構(gòu)所提供的系統(tǒng)函數(shù)的封裝膝舅,對(duì)外提供統(tǒng)一的系統(tǒng)調(diào)用接口