nginx模組開發
1. 配置-編譯-執行
./configure --add-module=ngx_module_echo/ --with-debug --with-cc-opt='-g'
make
make install
覆蓋 /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
需預先安裝的類庫
yum -y install pcre-devel openssl openssl-devel
2. 讀request
http/ngx_http_request.h裡定義了ngx_http_request_s的格式,包括
typedef struct{ ngx_str_t request_line; ngx_str_t uri; ngx_str_t args; ngx_str_t exten; ngx_str_t unparsed_uri; ngx_str_t method_name; ngx_str_t http_protocol; 。。。。}ngx_http_request_s
其中ngx_str_t的格式為
typedef struct { size_t len; u_char *data;} ngx_str_t
在handler函數裡可讀出來。
3. 寫響應體
首先,模組需要先聲明buffer和鏈表:
ngx_buf_t *b;ngx_chain_t out;
其中 ngx_chain_t 為
struct ngx_chain_s { ngx_buf_t *buf; ngx_chain_t *next;};
其中ngx_buf_t為
struct ngx_buf_s { u_char *pos; u_char *last; u_char *start; /* start of buffer */ u_char *end; /* end of buffer */ unsigned memory:1; unsigned last_buf:1; 。。。。。。};
接著,需要給buffer分配空間,並將我們的響應資料指向它:
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer."); return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = some_bytes; /* first position in memory of the data */ b->last = some_bytes + some_bytes_length; /* last position */ b->memory = 1; /* content is in read-only memory */ /* (i.e., filters should copy it rather than rewrite in place) */ b->last_buf = 1; /* there will be no more buffers in the request */
現在就可以把資料掛在鏈表上了:
out.buf = b;
out.next = NULL;
最後,我們發送這個響應體,傳回值是鏈表在一次調用後的狀態:(and return the status code of the output filter chain all in one go)
return ngx_http_output_filter(r, &out);
static ngx_int_t ngx_cc_answer(ngx_http_request_t *r, char *output){ngx_buf_t*b;ngx_chain_tout;ngx_str_tmessage;// 設定返回內容message.data = (unsigned char*)output;message.len = strlen(output);// 設定返回格式r->headers_out.content_type_len = sizeof("text/html") - 1;r->headers_out.content_type.len = sizeof("text/html") - 1;r->headers_out.content_type.data = (u_char *) "text/html";r->headers_out.status = NGX_HTTP_OK;r->headers_out.content_length_n = message.len;// 設定返回bufb = ngx_pcalloc(r->pool , sizeof(ngx_buf_t));if (b == NULL){return NGX_ERROR;}b->pos = message.data;b->last = message.data + message.len;b->memory = 1;b->last_buf = 1;out.buf = b;out.next = NULL;// 調用訊息發送函數ngx_http_send_header(r);return ngx_http_output_filter(r, &out);}
4 編譯c++模組
./configure --add-module=ngx_module_cpp/ --with-debug --without-http_rewrite_module --with-ld-opt="-lstdc++" --with-cc-opt='-g'
標頭檔加extern "C"
ngx_http_core_loc_conf_t*等類型需加強制轉換
5. 讀變數
用nginx提供的架構有一個致命的缺點:若變數值中含有&符號,那麼&後的字元會被當做另一種變數處理,導致變數值錯誤。所以,該方法僅適用於變數值簡單,不包含&分隔字元的情況,其它情況還是自行解析r->args王道(見2)。
1)在nginx中添加要讀的變數, 如 set $type $arg_type
2)讀變數函數
首先在ngx_task_module_ctx中註冊
static ngx_http_module_t ngx_task_module_ctx = { NULL, /* preconfiguration */ ngx_http_task_module_init, /* postconfiguration */ 。。。}
接著實現:
// 從設定檔中讀取type定義ngx_int_t ngx_http_task_module_init(ngx_conf_t *cf){ printf("called:ngx_http_task_module_init\n"); // 讀type參數 if ((ngx_http_type_index = ngx_http_task_module_add_variable(cf, &ngx_http_type_value)) == NGX_ERROR) { return NGX_ERROR; } return NGX_OK;}static ngx_int_t ngx_http_task_module_variable_not_found(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data){ v->not_found = 1; return NGX_OK;}static ngx_int_t ngx_http_task_module_add_variable(ngx_conf_t *cf, ngx_str_t *name){ ngx_http_variable_t *v; v = ngx_http_add_variable(cf, name, NGX_HTTP_VAR_CHANGEABLE); if (v == NULL) { return NGX_ERROR; } v->get_handler = ngx_http_task_module_variable_not_found; return ngx_http_get_variable_index(cf, name);}
3)加入讀變數邏輯
static ngx_int_t ngx_http_type_index;static ngx_str_t ngx_http_type_value = ngx_string("type");ngx_http_variable_value_t *type_vv;
handler中:
//讀取URL裡面具體的type變數的值 type_vv = ngx_http_get_indexed_variable(r,ngx_http_type_index); printf("%s\n", type_vv->data);
4)資料結構
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;
注意len表示data的長度。