Nginx 模塊開(kāi)發(fā)(學(xué)習(xí)筆記十八)

1. Nginx 介紹


?????Nginx是俄羅斯人編寫(xiě)的十分輕量級(jí)的HTTP服務(wù)器,它的發(fā)音為“engine X”, 是一個(gè)高性能的HTTP和反向代理服務(wù)器,同時(shí)也是一個(gè)IMAP/POP3/SMTP 代理服務(wù)器.Nginx是由俄羅斯人 Igor Sysoev為俄羅斯訪問(wèn)量第二的 Rambler.ru站點(diǎn)開(kāi)發(fā)的,從2004年開(kāi)始它已經(jīng)在該站點(diǎn)運(yùn)行了七八年了。Igor Sysoev在建立的項(xiàng)目時(shí),使用基于BSD許可。

英文主頁(yè):http://nginx.org.


?????Nginx以事件驅(qū)動(dòng)的方式編寫(xiě),所以有非常好的性能,同時(shí)也是一個(gè)非常高效的反向代理、負(fù)載平衡。

?????現(xiàn)在,Igor將源代碼以類BSD許可證的形式發(fā)布。Nginx因?yàn)樗姆€(wěn)定性、豐富的模塊庫(kù)、靈活的配置和低系統(tǒng)資源的消耗而聞名.業(yè)界一致認(rèn)為它是Apache+mod_proxy_balancer的輕量級(jí)代替者,不僅是因?yàn)轫憫?yīng)靜態(tài)頁(yè)面的速度非常快,而且它的模塊數(shù)量也非常非常豐富。對(duì)proxy?和 rewrite模塊的支持很徹底,還支持mod_fcgi、ssl、vhosts ,適合用來(lái)做mongrel clusters的前端HTTP響應(yīng)。

? nginx做為HTTP服務(wù)器,有以下幾項(xiàng)基本特性:

處理靜態(tài)文件,索引文件以及自動(dòng)索引;打開(kāi)文件描述符緩沖.

無(wú)緩存的反向代理加速,簡(jiǎn)單的負(fù)載均衡和容錯(cuò).

FastCGI,簡(jiǎn)單的負(fù)載均衡和容錯(cuò).

模塊化的結(jié)構(gòu)。包括gzipping, byte ranges, chunked responses,以及 SSI-filter等f(wàn)ilter。如果由FastCGI或其它代理服務(wù)器處理單頁(yè)中存在的多個(gè)SSI,則這項(xiàng)處理可以并行運(yùn)行,而不需要相互等待。

支持SSL 和 TLSSNI.

? Nginx專為性能優(yōu)化而開(kāi)發(fā),性能是其最重要的考量,實(shí)現(xiàn)上非常注重效率。它支持內(nèi)核 epoll、kqueue 等高性能并發(fā)模型,能經(jīng)受高負(fù)載的考驗(yàn)。

? Nginx具有很高的穩(wěn)定性。其它HTTP服務(wù)器,當(dāng)遇到訪問(wèn)的峰值,或者有人惡意發(fā)起慢速連接時(shí),也很可能會(huì)導(dǎo)致服務(wù)器物理內(nèi)存耗盡頻繁交換,失去響 應(yīng),只能重啟服務(wù)器。例如當(dāng)前apache一旦上到200個(gè)以上進(jìn)程,web響應(yīng)速度就明顯非常緩慢了。而Nginx采取了分階段資源分配技術(shù),使得它的 CPU與內(nèi)存占用率非常低。nginx官方表示保持10,000個(gè)沒(méi)有活動(dòng)的連接,它只占2.5M內(nèi)存,所以類似DOS這樣的攻擊對(duì)nginx來(lái)說(shuō)基本上 是毫無(wú)用處的。就穩(wěn)定性而言,nginx比lighthttpd更勝一籌。

? Nginx支持熱部署。它的啟動(dòng)特別容易, 并且?guī)缀蹩梢宰龅?*24不間斷運(yùn)行,即使運(yùn)行數(shù)個(gè)月也不需要重新啟動(dòng)。你還能夠在不間斷服務(wù)的情況下,對(duì)軟件版本進(jìn)行進(jìn)行升級(jí)。

? Nginx采用master-slave模型,能夠充分利用SMP的優(yōu)勢(shì),且能夠減少工作進(jìn)程在磁盤(pán)I/O的阻塞延遲。當(dāng)采用select()/poll()調(diào)用時(shí),還可以限制每個(gè)進(jìn)程的連接數(shù)。

? Nginx代碼質(zhì)量非常高,代碼很規(guī)范,手法成熟, 模塊擴(kuò)展也很容易。特別值得一提的是強(qiáng)大的Upstream與Filter鏈。 Upstream為諸如reverse proxy,與其他服務(wù)器通信模塊的編寫(xiě)奠定了很好的基礎(chǔ)。而Filter鏈最酷的部分就是各個(gè)filter不必等待前一個(gè)filter執(zhí)行完畢。它可以 把前一個(gè)filter的輸出做為當(dāng)前filter的輸入,這有點(diǎn)像Unix的管線。這意味著,一個(gè)模塊可以開(kāi)始?jí)嚎s從后端服務(wù)器發(fā)送過(guò)來(lái)的請(qǐng)求,且可以在 模塊接收完后端服務(wù)器的整個(gè)請(qǐng)求之前把壓縮流轉(zhuǎn)向客戶端。

? 當(dāng)然,nginx還很年輕,多多少少存在一些問(wèn)題,比如:Nginx是俄羅斯人創(chuàng)建,目前文檔方面還不是很完善.因?yàn)槲臋n大多是俄語(yǔ),所以文檔方面這也是個(gè)障礙.盡管nignx的模塊比較多,但它們還不夠完善。對(duì)腳本的支持力度不夠。

? 這些問(wèn)題,nginx的作者和社區(qū)都在努力解決,我們有理由相信nginx將繼續(xù)以高速的增長(zhǎng)率來(lái)分享輕量級(jí)HTTP服務(wù)器市場(chǎng),會(huì)有一個(gè)更美好的未來(lái)。


2. 準(zhǔn)備工作

去官方主頁(yè)http://nginx.org/下載最新的Nginx源碼包,這里給出目前最新的源碼包的直接連接:http://nginx.org/download/nginx-1.0.0.tar.gz


[zieckey@freebsd7.2 ~]$?mkdir nginx

[zieckey@freebsd7.2 ~]$?cd nginx

[zieckey@freebsd7.2 ~/nginx]$?wget http://nginx.org/download/nginx-1.0.0.tar.gz

[zieckey@freebsd7.2 ~/nginx]$?tar zxf nginx-1.0.0.tar.gz

[zieckey@freebsd7.2 ~/nginx]$?mkdir module_dev_urlquery

[zieckey@freebsd7.2 ~/nginx]$?cd module_dev_urlquery/

[zieckey@freebsd7.2 module_dev_urlquery]$

這里我們下載了 nginx-1.0.0 的源碼,然后準(zhǔn)備開(kāi)發(fā)一個(gè)?module_dev_urlquery 的module嵌入到nginx中

3. 準(zhǔn)備好?module_dev_urlquery?模塊的配置文件?

一個(gè) nginx module 一般都以個(gè)文件夾的方式存在,module源文件和該module的配置文件都在這個(gè)文件下面。

這里我們的module叫?module_dev_urlquery,其路徑為 /home/zieckey/nginx/module_dev_urlquery 。

其配置文件名為:config ,其路徑為?/home/zieckey/nginx/module_dev_urlquery/config

[zieckey@freebsd7.2 module_dev_urlquery]$ vim config


然后輸入以下內(nèi)容:


[zieckey@freebsd7.2 module_dev_urlquery]$?vim config

ngx_addon_name=ngx_http_p2s_module

HTTP_MODULES="$HTTP_MODULES ngx_http_p2s_module"

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


這里三行內(nèi)容稍稍解釋下:

第一行是表示這個(gè) nginx module 在程序中名字

第二行表示這是一個(gè)HTTP module,后面的名字與第一個(gè)行保存一致

第三是這個(gè)module的源文件路徑,值得說(shuō)明的是?$ngx_addon_dir 這個(gè)變量是 nginx 的內(nèi)置腳本的內(nèi)置變量,代表了這個(gè) module 的文件夾的絕對(duì)路徑,這里就是?/home/zieckey/nginx/module_dev_urlquery


4. 準(zhǔn)備源代碼文件?ngx_http_p2s_module.c?

這里的文件名和路徑必須與上面 config 文件中的一致

[zieckey@freebsd7.2 module_dev_urlquery]$ vim ngx_http_p2s_module.c

輸入以下源程序內(nèi)容:


#include?

#include?

#include?

typedef?struct?{

unsigned?long?consume;

char*?ini_buf;

size_t?buflen;//the lenght of the ini_buf

}?ngx_http_p2s_conf_t;

static?char?*ngx_http_p2s_urlquery_set(ngx_conf_t?*cf,?ngx_command_t?*cmd,?void?*conf);

static?void?*ngx_http_p2s_create_conf(ngx_conf_t?*cf);

static?uint8_t*?get_raw_http_body(?ngx_http_request_t*?r,?size_t*?body_len?);

static?ngx_command_t ngx_http_p2s_commands[]?=

{/*{{{*/

{?ngx_string("p2s_urlquery"),?//The command name, it MUST BE the same as nginx.conf location block's command

NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

ngx_http_p2s_urlquery_set,

0,

0,

NULL?},

ngx_null_command

};/*}}}*/

static?ngx_http_module_t ngx_http_p2s_module_ctx?=

{/*{{{*/

NULL,?/* preconfiguration */

NULL,?/* postconfiguration */

NULL,?/* create main configuration */

NULL,?/* init main configuration */

NULL,?/* create server configuration */

NULL,?/* merge server configuration */

ngx_http_p2s_create_conf,?/* create location configration */

NULL?/* merge location configration */

};/*}}}*/

ngx_module_t ngx_http_p2s_module?=

{/*{{{*/

NGX_MODULE_V1,

&ngx_http_p2s_module_ctx,?/* module context */

ngx_http_p2s_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

};/*}}}*/

/**

* @brief Get the HTTP body data from the ngx_http_request_t struct.

* @warning DONNOT release the return pointer.

* @param[in] ngx_http_request_t * r -

* The HTTP request of NGINX struct which holds the HTTP data.

* @param[out] size_t * body_len - The body data length will stored here.

* @return uint8_t* - A pointer to a memory where

* stored the HTTP body raw binary data.

* The memory is allocated from nginx memory pool,

* so the caller don't need to warry about the memory release work.

*/

static?uint8_t*?get_raw_http_body(?ngx_http_request_t*?r,?size_t*?body_len?)

{/*{{{*/

printf(?"%s\n",?__PRETTY_FUNCTION__?);

ngx_chain_t*?bufs?=?r->request_body->bufs;

*body_len?=?0;

ngx_buf_t*?buf?=?NULL;

uint8_t*?data_buf?=?NULL;

size_t?content_length?=?0;

if?(?r->headers_in.content_length?==?NULL?)

{

return?NULL;

}

// malloc space for data_buf

content_length?=?atoi(?(char*)(r->headers_in.content_length->value.data)?);

data_buf?=?(?uint8_t*?)ngx_palloc(?r->pool?,?content_length?+?1?);

size_t?buf_length?=?0;

while?(?bufs?)

{

buf?=?bufs->buf;

bufs?=?bufs->next;

buf_length?=?buf->last?-?buf->pos?;

if(?*body_len?+?buf_length?>?content_length?)

{

memcpy(?data_buf?+?*body_len,?buf->pos,?content_length?-?*body_len?);

*body_len?=?content_length?;

break;

}

memcpy(?data_buf?+?*body_len,?buf->pos,?buf->last?-?buf->pos?);

*body_len?+=?buf->last?-?buf->pos;

}

if?(?*body_len?)

{

data_buf[*body_len]?=?'\0';

}

return?data_buf;

}/*}}}*/

/**

* Process the client request.

* The client post data has stored in r

*/

static?void?p2s_urlquery_process_handler(ngx_http_request_t?*r)

{/*{{{*/

printf(?"%s\n",?__PRETTY_FUNCTION__?);

ngx_int_t rc?=?NGX_OK;

ngx_buf_t?*b?=?NULL;

ngx_chain_t out;

ngx_http_p2s_conf_t?*conf?=?NULL;

conf?=?(ngx_http_p2s_conf_t?*)ngx_http_get_module_loc_conf(r,?ngx_http_p2s_module);

if?(conf?==?NULL)

{

ngx_http_finalize_request(r,?NGX_HTTP_INTERNAL_SERVER_ERROR);

return?;

}

struct?timeval?tv;

gettimeofday(&tv,?NULL);

size_t?bodylen?=?0;

uint8_t*?contents?=?get_raw_http_body(?r,?&bodylen?);

printf(?"time=%f http body data len=%d:\n%s\n",?(tv.tv_sec?+?tv.tv_usec/1000000.0f?),?(int)bodylen,?(char*)contents?);

printf("----------------------http body data end-------------------\n");

/* Prepare for output, 128 is preserved for robust */

b?=?ngx_create_temp_buf(?r->pool,?128?+?conf->buflen?);

if?(b?==?NULL)

{

ngx_http_finalize_request(r,?NGX_HTTP_INTERNAL_SERVER_ERROR);

return?;

}

out.buf?=?b;

out.next?=?NULL;

b->last?=?ngx_sprintf(b->pos,?"%s",?conf->ini_buf);

r->headers_out.status?=?NGX_HTTP_OK;

r->headers_out.content_length_n?=?b->last?-?b->pos;

r->headers_out.content_type.len?=?sizeof("text/plain")?-?1;

r->headers_out.content_type.data?=?(u_char?*)?"text/plain";

b->last_buf?=?1;/* there will be no more buffers in the request */

rc?=?ngx_http_send_header(r);

if?(rc?==?NGX_ERROR?||?rc?>?NGX_OK?||?r->header_only)

{

ngx_http_finalize_request(r,?NGX_HTTP_INTERNAL_SERVER_ERROR);

return?;

}

ngx_http_output_filter(r,?&out);

ngx_http_finalize_request(r,?0);

}/*}}}*/

/**

* Reading data handler

* After read all the data from client we set a process handler

*/

static?ngx_int_t

ngx_http_p2s_urlquery_handler(ngx_http_request_t?*r)

{/*{{{*/

printf(?"%s\n",?__PRETTY_FUNCTION__?);

ngx_int_t rc?=?NGX_DONE;

rc?=?ngx_http_read_client_request_body(?r,?p2s_urlquery_process_handler?);

if?(rc?>=?NGX_HTTP_SPECIAL_RESPONSE)?{

return?rc;

}

return?NGX_DONE;

}/*}}}*/

/**

* set the request reading data handler

*/

static?char?*

ngx_http_p2s_urlquery_set(?ngx_conf_t?*cf,?ngx_command_t?*cmd,?void?*conf?)

{/*{{{*/

printf(?"%s\n",?__PRETTY_FUNCTION__?);

ngx_http_core_loc_conf_t?*clcf;

clcf?=?(ngx_http_core_loc_conf_t?*)ngx_http_conf_get_module_loc_conf(cf,?ngx_http_core_module);

clcf->handler?=?ngx_http_p2s_urlquery_handler;

return?NGX_CONF_OK;

}/*}}}*/

static?void?*

ngx_http_p2s_create_conf(ngx_conf_t?*cf)

{/*{{{*/

printf(?"%s\n",?__PRETTY_FUNCTION__?);

ngx_http_p2s_conf_t?*conf;

conf?=?(ngx_http_p2s_conf_t?*)ngx_pcalloc(cf->pool,?sizeof(ngx_http_p2s_conf_t));

if?(conf?==?NULL)?{

return?NGX_CONF_ERROR;

}

conf->consume?=?0;

/* we open the nginx config file and send it back to client*/

FILE?*fp?=?fopen(?"../conf/nginx.conf",?"r");

if(?fp?==?NULL?)

{

return?NGX_CONF_ERROR;

}

fseek(fp,?0,?SEEK_END);

long?len?=?ftell(?fp?);

if?(?len?<?0?)

{

return?NGX_CONF_ERROR;

}

conf->buflen?=?(size_t)(len?+?1);

conf->ini_buf?=?(char?*)ngx_palloc(?cf->pool,?len?+?1?);

fseek(fp,?0,?SEEK_SET);

fread(conf->ini_buf,?1,?len,?fp);

conf->ini_buf[len]?=?0;

fclose(fp);

return?conf;

}/*}}}*/


5. 編譯運(yùn)行

現(xiàn)在可以編譯nginx和我們剛剛寫(xiě)好的模塊了。


[zieckey@freebsd7.2 ~/nginx]$?cd

[zieckey@freebsd7.2 ~]$?cd nginx/

[zieckey@freebsd7.2 ~/nginx]$?mkdir bininstalled

[zieckey@freebsd7.2 ~/nginx]$?cd nginx-1.0.0

[zieckey@freebsd7.2 nginx-1.0.0]$?./configure?--add-module=/home/zieckey/nginx/module_dev_urlquery?--prefix=/home/zieckey/nginx/bininstalled

./configure:?error:?the HTTP rewrite module requires the PCRE library.

You can either disable the module by using?--without-http_rewrite_module

option,?or?install the PCRE library?into?the system,?or?build the PCRE library

statically from the source with nginx by using?--with-pcre=?option.

第一次錯(cuò)誤,我們現(xiàn)在這個(gè)freebsd系統(tǒng)上沒(méi)有pcre庫(kù),太悲催了,不過(guò)還好,這里給出了提示,說(shuō)可以通過(guò) --without-http_rewrite_module 來(lái)禁用使用pcre庫(kù)的 HTTP rewrite 模塊,我們?cè)囈辉嚕?/p>

[zieckey@freebsd7.2 nginx-1.0.0]$?./configure?--add-module=/home/zieckey/nginx/module_dev_urlquery?--prefix=/home/zieckey/nginx/bininstalled?--without-http_rewrite_module

adding module?in?/home/zieckey/nginx/module_dev_urlquery

+?ngx_http_p2s_module was configured

重點(diǎn)看到上面幾行信息,說(shuō)明我們自己寫(xiě)的模塊module_dev_urlquery已經(jīng)被nginx接納,生成makefile成功。

[zieckey@freebsd7.2 nginx-1.0.0]$?make

[zieckey@freebsd7.2 nginx-1.0.0]$?make install

[zieckey@freebsd7.2 nginx-1.0.0]$?cd /home/zieckey/nginx/bininstalled/

[zieckey@freebsd7.2 bininstalled]$?ls

conf html logs sbin

[zieckey@freebsd7.2 bininstalled]$?cd conf

[zieckey@freebsd7.2 conf]$?vim ngi

nginx.conf nginx.conf.default

[zieckey@freebsd7.2 conf]$?vim nginx.conf

默認(rèn)的配置文件是下面(將‘#’開(kāi)頭的注釋行刪除之后)

worker_processes 1;

events {

worker_connections 1024;

}

http {

include?mime.types;

default_type application/octet-stream;

sendfile?on;

keepalive_timeout 65;

server {

listen?80;

server_name localhost;

location?/ {

root html;

index index.html index.htm;

}

}

}

我們?cè)谧钌厦嫣砑尤缦逻x項(xiàng):daemon off;? 可以讓程序不以daemon的方式運(yùn)行,這樣我們可以看到一些調(diào)試的打印信息。

另外,在 server 里面添加一個(gè) URI :

location /urlquery {

p2s_urlquery;

}

最后,我們修改下http監(jiān)聽(tīng)的端口號(hào),從默認(rèn)的80改為8088,因?yàn)橛行r(shí)候,我們并沒(méi)有權(quán)限在80端口上監(jiān)聽(tīng)連接。

修改之后的配置文件全文如下:

daemon?off;

worker_processes 1;

events {

worker_connections 1024;

}

http {

include?mime.types;

default_type application/octet-stream;

sendfile?on;

keepalive_timeout 65;

server {

listen?8088;

server_name localhost;

location?/ {

root html;

index index.html index.htm;

}

location?/urlquery {

p2s_urlquery;

}

}

}

好了,到此為止,我們的所有工作就都準(zhǔn)備好了,可以啟動(dòng)nginx

[zieckey@freebsd7.2 conf]$?cd /home/zieckey/nginx/bininstalled/sbin/

[zieckey@freebsd7.2 sbin]$?./nginx

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_urlquery_set

新開(kāi)一個(gè)終端,用curl來(lái)發(fā)起一個(gè)http post請(qǐng)求,post數(shù)據(jù)由-d參數(shù)指定:

[zieckey@freebsd7.2 ~]$?curl?-d?"user=zieckey&verifykey=123456"?http://localhost:8088/urlquery

daemon off;

worker_processes 1;

events {

worker_connections 1024;

}

http {

include?mime.types;

default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

server {

listen 8088;

server_name localhost;

location / {

root html;

index index.html index.htm;

}

location /urlquery {

p2s_urlquery;

}

}

}

[zieckey@freebsd7.2 ~]$

然后可以看看nginx服務(wù)器的一些輸出信息:

[zieckey@freebsd7.2 sbin]$?./nginx

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_create_conf

ngx_http_p2s_urlquery_set

ngx_http_p2s_urlquery_handler

p2s_urlquery_process_handler

get_raw_http_body

time=1303552000.000000 http body data len=29:

user=zieckey&verifykey=123456

----------------------http body data end-------------------


6. 其他說(shuō)明

6.1?配置文件和ngx_command_t的對(duì)應(yīng)關(guān)系:

static ngx_command_t ngx_http_p2s_commands[]?=

{/*{{{*/

{ ngx_string("p2s_urlquery"),?// 命令名,請(qǐng)對(duì)照 nginx.conf 看這個(gè)

NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,

ngx_http_p2s_urlquery_set,

0,

0,

NULL },

ngx_null_command

};/*}}}*/

nginx.conf 中的 location 字段的配置是這樣的:

location /urlquery {

p2s_urlquer;

}


這里的?/urlquery 是 URL 請(qǐng)求里的 URI 部分,

例如http://localhost/urlquery這條URL的請(qǐng)求會(huì)被這條配置項(xiàng)處理,

這條配置項(xiàng),會(huì)去找命令名為“p2s_urlquery”的 ngx_command 去處理。


6.2 模塊名

代碼中的模塊變量名必須與config配置文件的名字一致

config 配置文件的內(nèi)容:ngx_addon_name=ngx_http_p2s_module

代碼中的內(nèi)容:


ngx_module_t ngx_http_p2s_module?=

{/*{{{*/

NGX_MODULE_V1,

&ngx_http_p2s_module_ctx,?/*?module context?*/

ngx_http_p2s_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

};/*}}}*/


模塊的config配置文件會(huì)幫助 configure 生成一個(gè)ngx_modules.c文件,該文件里會(huì)引用?ngx_module_t? ngx_http_p2s_module 這個(gè)外部定義的變量,所以必須保持一致。在執(zhí)行 ./configure 完后,在nginx-1.0.0源碼的根目錄會(huì)多出來(lái)一個(gè)文件夾objs,在這里可以找到ngx_modules.c文件。


6.3 代碼調(diào)用關(guān)系

nginx程序啟動(dòng)的時(shí)候,會(huì)去讀配置文件 conf/nginx.conf ,每讀到一個(gè)配置項(xiàng),就會(huì)調(diào)用 module 注冊(cè)的回調(diào)函數(shù),所以這里可以看到nginx啟動(dòng)的時(shí)候調(diào)用?ngx_http_p2s_create_conf 函數(shù)好幾次。 這個(gè)函數(shù)是由?


static ngx_http_module_t ngx_http_p2s_module_ctx?=

{/*{{{*/

NULL,?/*?preconfiguration?*/

NULL,?/*?postconfiguration?*/

NULL,?/*?create main configuration?*/

NULL,?/*?init main configuration?*/

NULL,?/*?create server configuration?*/

NULL,?/*?merge server configuration?*/

ngx_http_p2s_create_conf,?/*?create location configration?*/

NULL /*?merge location configration?*/

};/*}}}*/

指定的。


然后,在一個(gè)客戶端發(fā)起http請(qǐng)求的時(shí)候,例如我們這里的 “curl http://localhost:8088/urlquery” 命令實(shí)際上是發(fā)起一個(gè) http 請(qǐng)求,URI 是 urlquery,所以,nginx 根據(jù)配置文件的配置項(xiàng),找到??urlquery 對(duì)應(yīng)的處理模塊名?p2s_urlquery, 然后調(diào)用 p2s_urlquery 這個(gè)名字關(guān)聯(lián)的?ngx_http_p2s_urlquery_set 回調(diào)函數(shù)。

ngx_http_p2s_urlquery_set?回調(diào)函數(shù)又會(huì)設(shè)置一個(gè)?ngx_http_p2s_urlquery_handler 回調(diào)函數(shù),ngx_http_p2s_urlquery_handler 回調(diào)函數(shù)會(huì)在 nginx 讀取客戶端發(fā)過(guò)來(lái)的http數(shù)據(jù)的時(shí)候被調(diào)用。

ngx_http_p2s_urlquery_handler 又會(huì)設(shè)置一個(gè)?p2s_urlquery_process_handler 回調(diào)函數(shù),

p2s_urlquery_process_handler 會(huì)在?nginx 讀取完客戶端發(fā)過(guò)來(lái)的http數(shù)據(jù)之后的時(shí)候被調(diào)用,

不難發(fā)現(xiàn),p2s_urlquery_process_handler函數(shù)是我們真正的處理邏輯,因?yàn)檫@個(gè)時(shí)候已經(jīng)收完了客戶端的http數(shù)據(jù)。


p2s_urlquery_process_handler 函數(shù)先調(diào)用?get_raw_http_body 這個(gè)我們自己封裝的函數(shù)將客戶端發(fā)送過(guò)來(lái)的 http data 讀取到一個(gè)緩沖區(qū)中,然后處理(這里我們只是簡(jiǎn)單的printf)。然后,我們準(zhǔn)備好數(shù)據(jù),發(fā)送會(huì)客戶端。


到此,我們完成了一個(gè)很簡(jiǎn)單的模塊的開(kāi)發(fā)和調(diào)試工作,也不是那么困難。

同時(shí)對(duì)一些函數(shù)調(diào)用,配置文件關(guān)系等等比較含糊的地方做了詳細(xì)說(shuō)明。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。