本文開發一個nginx http模塊基本的開發步驟和前篇http://www.cnblogs.com/yjf512/archive/2013/06/10/3130890.html 說的一樣,按照開發的六個步驟寫。
配置文件及功能
該模塊的功能是驗證請求url中的secret參數的值是否是約定的秘鑰。
它的nginx配置文件是這樣的:
worker_processes 1; error_log logs/error.log debug; master_process off; daemon off; events { worker_connections 1024; } http { default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8001; server_name localhost; access_log /tmp/access.log; error_log /tmp/error.log debug; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location = /mysecert { # 只有傳遞的secret參數值為secretpassword的時候才通過驗證 # 1 通過驗證頁面顯示“secret right” # 2 不通過驗證頁面顯示“secret wrong” # 比如 # http://abc.com:8001?secret=secretpassword通過 # http://abc.com:8001?secret=123不通過 mysecret secretpassword; } } }
location為/mysecret的時候,需要傳遞值為secretpassword的mysecret參數。頁面會返回200並顯示secret right,否則頁面返回200並顯示secret wrong。
配置文件這里有幾個地方注意下:
為了調試方便,調整了幾個地方:
worker_processes 1; master_process off; daemon off; … access_log /tmp/access.log; error_log /tmp/error.log debug;
而且在configure的時候我也加上了--with-debug參數
./configure --add-module=/home/yejianfeng/nginx/nginx_module/mysecret2/ --prefix=/home/yejianfeng/nginx/nginx/ --with-debug
這樣讓調試更加方便
具體代碼
完整的代碼可以看:https://github.com/jianfengye/MyWorks/tree/master/nginx_module_mysecret
有幾個地方要說明:
1 這個模塊由於有從配置文件中讀取的信息,所以它是有屬於自己模塊的配置文件結構的
typedef struct { ngx_str_t secret; } ngx_http_mysecret_conf_t;
所以有自己的配置文件,那么在模塊構造模塊上下文的時候create_loc_conf的階段就多一個功能是初始化配置文件結構
// 定義上下文, 只會在location中出現,所以都為null
static ngx_http_module_t ngx_http_mysecret_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ngx_http_mysecret_create_loc_conf, //這里有使用自己的配置結構
NULL
};
其中ngx_http_mysecret_create_loc_conf只要做的事情是初始化配置文件
2 如何將配置文件nginx.conf中的mysecret的一個參數放在配置文件結構中呢?
在ngx_http_mysecret這個命令回調函數中,有個ngx_conf_set_str_slot,這個是nginx預設的14個讀取配置文件的函數之一,調用它就可以把nginx.conf中的secrect秘鑰讀取到配置文件結構中了。
3 在handler中怎么獲取配置文件結構呢?
現在讀取配置文件結束了,也構造了配置文件結構,到具體的處理http請求的階段,如何獲取這個結構呢?
ngx_http_mysecret_conf_t *mycf; mycf = ngx_http_get_module_loc_conf(r, ngx_http_mysecret_module);
使用這個方法就能在handler中獲取到自定義的配置文件結構了。
獲取配置結構后,后面的問題就是如何獲取請求參數呢
ngx_http_request_t中的args參數就是獲取請求參數的
比如http://abc.com?a=s&b=2 那么args就是ngx_string("a=s&b=2")
后面就可以使用nginx自定義的ngx_strncasecmp進行字符比較等操作了。
好了,完整的一個驗證請求參數的模塊就寫完了。
模塊變種
有人會對nginx.conf文件有點不舒服,可能希望設置驗證秘鑰是分為兩個步驟:
設置秘鑰和驗證秘鑰
即配置文件大致變成現在的樣子:
location = /mysecert { # 只有傳遞的secret參數值為secretpassword的時候才通過驗證 # 1 通過驗證頁面顯示“secret right” # 2 不通過驗證頁面顯示“secret wrong” # 比如 # http://abc.com:8001?secret=secretpassword通過 # http://abc.com:8001?secret=123不通過 setmysecret secretpassword; checksecret; }
原來的mysecret被兩個命令setmysecret和checksecret替換了
這兩個命令的功能其實是不一樣的,setmysecret只是讀取配置文件,並不會對請求做任何操作,而checksecret是直接修改請求的。
其實上一個例子稍微改一改就可以達到這樣的目的:
https://github.com/jianfengye/MyWorks/tree/master/nginx_module_mysecret2
定義模塊命令的結構就變成:
static ngx_command_t ngx_http_mysecret_commands[] = { { ngx_string("setmysecret"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_mysecret_conf_t, secret), NULL, }, { ngx_string("checksecret"), NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, ngx_http_mysecret, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL, }, ngx_null_command };
這里的setmysecret直接使用nginx預設的ngx_conf_set_str_slot方法,它就不需要有任何定義handler的操作了。事實上,nginx很多模塊的像setmysecret這樣的讀取配置文件的命令(不做任何http請求的操作)都是直接使用nginx預設的14種方法的。具體的使用在《深入理解Nginx》第四章中有詳細說明了。
自然在checksecret命令中就不需要再讀取參數了(也沒有參數了,所以要注意這個命令中的命令類型要設置上NGX_CONF_NOARGS)