NGINX模塊開(kāi)發(fā)

目標(biāo):在nginx層面增加一個(gè)模塊對(duì)請(qǐng)求進(jìn)行處理(例如:給每個(gè)請(qǐng)求生成一個(gè)ID产场,生成ID之后鹅髓,通過(guò)PHP語(yǔ)言可以獲取到該ID)

簡(jiǎn)介:

1、NGINX對(duì)一個(gè)請(qǐng)求的處理過(guò)程

NGINX將http請(qǐng)求劃分為11個(gè)處理階段

階段 說(shuō)明
NGX_HTTP_POST_READ_PHASE 接收到完整的HTTP頭部后處理的階段
NGX_HTTP_SERVER_REWRITE_PHASE 請(qǐng)求的URI與nginx.conf中的location表達(dá)式匹配前京景,修改請(qǐng)求的URI是一個(gè)獨(dú)立的http階段(重定向)
NGX_HTTP_FIND_CONFIG_PHASE 根據(jù)請(qǐng)求的URI尋找匹配的location表達(dá)式窿冯,該階段只能由ngx_http_core_module模塊實(shí)現(xiàn),不建議其他http模塊重新定義這一階段的行為
NGX_HTTP_REWRITE_PHASE 根據(jù)上一階段找到的匹配的location表達(dá)式修改URI
NGX_HTTP_POST_REWRITE_PHASE 防止由于nginx.conf配置錯(cuò)誤導(dǎo)致的重寫(xiě)URL后的死循環(huán)确徙,防止死循環(huán)的處理方法:一個(gè)請(qǐng)求重寫(xiě)URL的次數(shù)達(dá)到10次就認(rèn)為死循環(huán)醒串,nginx會(huì)返回500錯(cuò)誤
NGX_HTTP_PREACCESS_PHASE NGX_HTTP_ACCESS_PHASE階段決定訪問(wèn)權(quán)限前执桌,HTTP模塊 可以介入的階段
NGX_HTTP_ACCESS_PHASE 讓HTTP模塊判斷是否允許這個(gè)請(qǐng)求訪問(wèn)nginx服務(wù)器
NGX_HTTP_POST_ACCESS_PHASE 給上一階段收尾,如果NGX_HTTP_ACCESS_PHASE階段的HTTP模塊的handler函數(shù)返回請(qǐng)求沒(méi)有權(quán)限訪問(wèn)(NGX_HTTP_FORBIDEN或者NGX_HTTP_UNAUTHORIZED)厦凤,該階段向用戶(hù)發(fā)送拒絕服務(wù)的錯(cuò)誤碼
NGX_HTTP_TRY_FILES_PHASE 該階段為了nginx中的try_files配置項(xiàng)而設(shè)置鼻吮,當(dāng)HTTP訪問(wèn)靜態(tài)資源時(shí),try_files配置項(xiàng)可以使請(qǐng)求順序的訪問(wèn)多個(gè)靜態(tài)資源较鼓,如果某一次訪問(wèn)失敗椎木,繼續(xù)訪問(wèn)下一靜態(tài)資源。這個(gè)功能是在該階段中實(shí)現(xiàn)的博烂。
NGX_HTTP_CONTENT_PHASE 處理HTTP請(qǐng)求內(nèi)容的階段香椎,該階段是大部分HTTP模塊最愿意介入的階段
NGX_HTTP_LOG_PHASE 處理請(qǐng)求完畢后記錄請(qǐng)求日志的階段。ngx_http_log_module模塊在這一階段加入一個(gè)handler方法禽篱,每個(gè)請(qǐng)求 處理完畢后記錄access_log日志

自定義HTTP模塊無(wú)法介入的階段:

NGX_HTTP_FIND_CONFIG_PHASE
NGX_HTTP_POST_REWRITE_PHASE
NGX_HTTP_POST_ACCESS_PHASE
NGX_HTTP_TRY_FILES_PHASE

剩余7個(gè)模塊均可以介入畜伐,每個(gè)階段可以介入模塊的個(gè)數(shù)也是沒(méi)有限制的,多個(gè)模塊可以介入同一階段處理同一請(qǐng)求躺率。


下面記錄的模塊介入的階段:NGX_HTTP_CONTENT_PHASE(處理HTTP請(qǐng)求內(nèi)容)

介入NGX_HTTP_CONTENT_PHASE的方法有兩種玛界,一種介入方法是處理所有請(qǐng)求,一種介入方法是只處理特定的請(qǐng)求悼吱。

下面的介入方法是處理所有請(qǐng)求慎框。
NGINX中關(guān)于HTTP階段的一些處理方法見(jiàn)下一篇(鏈接)

1、增加編譯的配置文件(將自定義HTTP模塊編譯進(jìn)nginx)

自定義模塊的一般目錄結(jié)構(gòu):

+ ngx_http_xxxxxx_module

  -config

  -ngx_http_xxxxxx_module.c

config文件:編譯nginx可執(zhí)行文件時(shí)后添,會(huì)讀取該文件獲取模塊相關(guān)路徑及模塊名稱(chēng)等

ngx_http_xxxxxx_module.c :處理http請(qǐng)求的代碼文件

舉例:


ngx_addon_name=ngx_http_xxxxxx_module

HTTP_MODULES="$HTTP_MODULES ngx_http_xxxxxx_module"

NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_xxxxxx_module.c"

// ngx_addon_name:模塊名稱(chēng)

// HTTP_MODULES:所有的http處理模塊笨枯,自定義模塊前一定要加上$HTTP_MODULES,該變量表示已經(jīng)存在的http模塊

//  NGX_ADDON_SRCS:模塊源文件遇西,$NGX_ADDON_SRCS表示已有的模塊源文件路徑馅精,$ngx_addon_dir表示使用.configure命令時(shí)輸入的路徑

// 編譯命令:

// .configure  --prefix=/usr/local/adinf/nginx-1.10.3 --with-stream --with-stream_ssl_module --with-http_ssl_module --with-threads --add-module=/data1/htdocs/ngx_http_xxxxxx_module

2、ngx_http_xxxxxx_module.c部分

簡(jiǎn)介:

nginx中的模塊分類(lèi)幾類(lèi):核心模塊粱檀,事件模塊洲敢,http模塊,upstream模塊茄蚯,郵件模塊等

核心模塊

typedef struct {
    ngx_str_t xxxxxx_config_value;
} ngx_http_xxxxxx_conf_t;


static ngx_command_t ngx_http_xxxxxx_commands[] = {
   {
        ngx_string("xxxxxx"),   // nginx.conf中沦疾,該模塊會(huì)處理的配置項(xiàng)名稱(chēng)
        NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, // 該名稱(chēng)的配置項(xiàng)在conf中允許的配置方式;NGX_HTTP_SRV_CONF表示允許在server塊下出現(xiàn)第队,NGX_CONF_TAKE1表示配置項(xiàng)名稱(chēng)后可以跟一個(gè)參數(shù)
        ngx_http_xxxxxx_handler_conf,        //解析配置該配置項(xiàng)對(duì)應(yīng)的方法
        NGX_HTTP_SRV_CONF_OFFSET,
        offsetof(ngx_http_xxxxxx_conf_t, xxxxxx),//該配置項(xiàng)對(duì)應(yīng)的參數(shù)會(huì)被保存到ngx_http_xxxxxx_conf_t的成員xxxxxx中
        NULL
    },

    ngx_null_command

};


static ngx_http_module_t  ngx_http_xxxxxx_module_ctx = {
    ngx_http_xxxxxx_add_variable,      /* preconfiguration */
    ngx_http_xxxxxx_init,              /* postconfiguration */
    NULL,                              /* create main configuration */
    NULL,                              /* init main configuration */
    ngx_http_xxxxxx_create_srv_conf,    /* create server configuration */
    NULL,                              /* merge server configuration */
    ngx_http_xxxxxx_create_loc_conf,    /* create location configuration */
    ngx_http_xxxxxx_merge_loc_conf,    /* merge location configuration */
};

ngx_module_t  ngx_http_xxxxxx_module = {

    NGX_MODULE_V1,

    &ngx_http_xxxxxx_module_ctx,          /* module context */
    ngx_http_xxxxxx_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

};
ngx_http_xxxxxx_module:

nginx中有一個(gè)模塊的數(shù)據(jù)結(jié)構(gòu)ngx_module_t,所有的nginx模塊都要遵循ngx_module_t的定義刨秆。nginx啟動(dòng)時(shí)會(huì)調(diào)用模塊中定義的方法凳谦。ngx_module_t中最重要的是要設(shè)置ctxcommands兩個(gè)成員。ctx用于指向一類(lèi) 模塊的上下文衡未,http類(lèi)模塊中需要指向ngx_http_module_t結(jié)構(gòu)體尸执。commands將處理nginx.conf中的配置項(xiàng)家凯。

NGX_HTTP_MODULE表示該模塊為http模塊。

NGX_MODULE_V1NGX_MODULE_V1_PADDING兩個(gè)宏定義模塊中未用到的成員的初始值如失。

上面的定義中ctx指向ngx_http_xxxxxx_module_ctx,commands設(shè)置為ngx_http_xxxxxx_commands绊诲。

ngx_http_xxxxxx_module_ctx:

ngx_http_module_t結(jié)構(gòu)體定義了8個(gè)階段,nginx啟動(dòng)過(guò)程中褪贵,會(huì)調(diào)用結(jié)構(gòu)體定義的相關(guān)方法掂之。

調(diào)用順序:

階段 說(shuō)明
create main configuration 創(chuàng)建存儲(chǔ)main級(jí)別直屬于http塊的結(jié)構(gòu)體
create server configuration 創(chuàng)建存儲(chǔ)conf中直屬于server塊的配置的結(jié)構(gòu)體
create location configuration 創(chuàng)建存conf中直屬于location塊的配置的結(jié)構(gòu)體
preconfiguration 解析配置文件前
init main configuration 初始化main級(jí)別配置項(xiàng)
merge server configuration 合并main級(jí)別和server級(jí)別下同名的配置項(xiàng)
merge location configuration 合并server級(jí)別和location級(jí)別下的同名配置項(xiàng)
postconfiguration 完成配置項(xiàng)解析

示例代碼中

方法ngx_http_xxxxxx_add_variable在解析配置文件前創(chuàng)建一個(gè)了一個(gè)變量,具體方法實(shí)現(xiàn)看后續(xù)代碼

方法ngx_http_xxxxxx_init則設(shè)置了NGX_HTTP_CONTENT_PHASE階段的處理http請(qǐng)求的方法脆丁,具體方法實(shí)現(xiàn)看后續(xù)代碼

ngx_http_xxxxxx_commands:解析nginx.conf

// ngx系統(tǒng)方法解析配置項(xiàng)
static char * ngx_http_xxxxxx_handler_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_conf_set_str_slot(cf, cmd, conf);    //調(diào)用ngx_conf_set_str_slot 處理ngx_str_t類(lèi)型的變量
    return NGX_CONF_OK;
}

ngx_http_xxxxxx_handler_conf方法解析nginx.conf配置世舰,會(huì)將config中配置的值解析到結(jié)構(gòu)體ngx_http_xxxxxx_conf_t中。該方法在nginx啟動(dòng)過(guò)程中被調(diào)用槽卫。

static ngx_str_t xxxxxx_variable = ngx_string("xxxxxx_variable"); // 要添加的變量名

// 增加變量
static ngx_int_t ngx_http_xxxxxx_add_variable(ngx_conf_t *cf){

    ngx_http_variable_t * var;
    var = ngx_http_add_variable(cf, &xxxxxx_variable, 0);

    if (var == NULL) {
        return NGX_OK;
    }

    //設(shè)置回調(diào)
    var->get_handler = ngx_http_variable_xxxxxx_variable; // 獲取該變量時(shí)的回調(diào)方法
    var->data = 0;

    return NGX_OK;
}

typedef struct {
    ngx_str_t xxxxxx_value;
} ngx_http_xxxxxx_ctx_t;

ngx_int_t ngx_http_variable_xxxxxx_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data)
{

    ngx_http_xxxxxx_ctx_t *ctx;
    ctx = ngx_http_get_module_ctx(r, ngx_http_xxxxxx_module);

    if (ctx == NULL) {
        v->not_found = 1;
        return NGX_OK;
    }

    v->len = ctx->xxxxxx_value.len;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;
    v->data = ctx->xxxxxx_value.data;
    return NGX_OK;

}

nginx中的變量分為三種:模塊內(nèi)置變量跟压、根據(jù)配置動(dòng)態(tài)添加的變量內(nèi)置規(guī)則變量

該示例中添加的變量屬于模塊內(nèi)置變量歼培。

根據(jù)配置動(dòng)態(tài)添加的變量一般當(dāng)解析相應(yīng)指令時(shí)震蒋,在指令的解析函數(shù)中添加。

內(nèi)置規(guī)則變量不需要添加躲庄,而是按特定規(guī)則解析查剖,例如http、upstream_http读跷、arg梗搅、cookie等變量都是nginx根據(jù)請(qǐng)求解析的。

模塊內(nèi)置變量主要是在ngx_http_module_tpreconfiguration階段中添加(也即在nginx框架解析配置文件前)效览。

模塊內(nèi)置變量和根據(jù)配置動(dòng)態(tài)添加的變量都是通過(guò)調(diào)用ngx_http_add_variable()方法添加變量无切。ngx_http_add_variable方法會(huì)向存儲(chǔ)配置項(xiàng)的結(jié)構(gòu)體ngx_conf_t->variable_key數(shù)組中添加變量(參數(shù)是ngx_conf_t參數(shù)名等)并返回變量結(jié)構(gòu)。

// nginx中變量結(jié)構(gòu)體的數(shù)據(jù)結(jié)構(gòu)(并非示例代碼)
typedef ngx_variable_value_t  ngx_http_variable_value_t;

typedef struct {

unsigned    len:28; //  變量值數(shù)據(jù)長(zhǎng)度
unsigned    valid:1;  // 該變量值是否可用
unsigned    no_cacheable:1; // 該變量值是否不能緩存
unsigned    not_found:1;  // 對(duì)應(yīng)變量不存在
unsigned    escape:1;  // 變量值內(nèi)容中的特殊字符是否進(jìn)行了轉(zhuǎn)義

u_char      *data;  // 變量值的數(shù)據(jù)
}  ngx_variable_value_t;

nginx所有變量都存儲(chǔ)在ngx_http_core_modulemain級(jí)別的結(jié)構(gòu)體ngx_http_core_main_conf_t中丐枉,所以變量的作用范圍是整個(gè)http{}配置哆键。在某個(gè)server中添加的變量,在另一個(gè)server同樣可以使用瘦锹。

本示例每個(gè)http請(qǐng)求處理過(guò)程中都會(huì)更新一下變量籍嘹,所以每個(gè)請(qǐng)求變量值都不一樣

// 設(shè)置某個(gè)階段處理請(qǐng)求的方法
static ngx_int_t ngx_http_xxxxxx_init(ngx_conf_t *cf)
{
    ngx_http_handler_pt        *w;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = (ngx_http_core_main_conf_t*)ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    //在NGX_HTTP_CONTENT_PHASE中介入處理代碼,回調(diào)函數(shù)ngx_http_xxxxxx_handler_request可對(duì)http請(qǐng)求做處理
    w = (ngx_http_handler_pt*)ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);

    if (w == NULL)
    {
        return NGX_OK;
    }

    //具體實(shí)現(xiàn)的回調(diào)函數(shù)
    *w = ngx_http_xxxxxx_handler_request;

    return NGX_OK;

}

nginx相關(guān)配置:

  • nginx.conf中在server下增加配置項(xiàng) xxxxxx xxxxxxxxxx
  • fastcgi_params中增加變量配置
  • php中通過(guò)$_SERVER['變量名']使用弯院,變量名 使用fastcgi_params中配置的變量|
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辱士,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子听绳,更是在濱河造成了極大的恐慌颂碘,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椅挣,死亡現(xiàn)場(chǎng)離奇詭異头岔,居然都是意外死亡塔拳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)峡竣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)靠抑,“玉大人,你說(shuō)我怎么就攤上這事适掰∷瘫蹋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵攻谁,是天一觀的道長(zhǎng)稚伍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)戚宦,這世上最難降的妖魔是什么个曙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮受楼,結(jié)果婚禮上垦搬,老公的妹妹穿的比我還像新娘。我一直安慰自己艳汽,他們只是感情好猴贰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著河狐,像睡著了一般米绕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上馋艺,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天栅干,我揣著相機(jī)與錄音,去河邊找鬼捐祠。 笑死碱鳞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的踱蛀。 我是一名探鬼主播窿给,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼率拒!你這毒婦竟也來(lái)了崩泡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤猬膨,失蹤者是張志新(化名)和其女友劉穎允华,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡靴寂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了召耘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片百炬。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖污它,靈堂內(nèi)的尸體忽然破棺而出剖踊,到底是詐尸還是另有隱情,我是刑警寧澤衫贬,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布德澈,位于F島的核電站,受9級(jí)特大地震影響固惯,放射性物質(zhì)發(fā)生泄漏梆造。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一葬毫、第九天 我趴在偏房一處隱蔽的房頂上張望镇辉。 院中可真熱鬧,春花似錦贴捡、人聲如沸忽肛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)屹逛。三九已至,卻和暖如春汛骂,著一層夾襖步出監(jiān)牢的瞬間罕模,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工香缺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留手销,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓图张,卻偏偏與公主長(zhǎng)得像锋拖,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子祸轮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容