從前面的篇章中,我們基本瞭解了Nginx的運行原理。Nginx整個架構都是通過模組的方式,對整個系統進行解耦和擴充。
在HTTP的http/modules/目錄下,有非常多的關於HTTP協議的模組,每個模組都有不同的功能。
接下去我們就需要建立一個自訂的模組。
建立擴充模組目錄 我們在nginx-1.13.1檔案夾下,建立一個 /extends/ngx_http_hello_module的目錄
建立config檔案 我們的模組名稱為: ngx_http_hello_module 我們需要建立一個config檔案,這樣Nginx在編譯的時候,會將你自訂的模組編譯進去。 config檔案中配置如下:
ngx_addon_name=ngx_http_hello_moduleHTTP_MODULES="$HTTP_MODULES ngx_http_hello_module"NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c"
建立ngx_http_hello_module.c檔案 建立自訂的模組必須遵守Nginx的模組規範,需要定義: 1. ngx_command_t 命令列解析結構 2. ngx_http_module_t 模組的上下文結構 3. ngx_module_t 模組結構 如果對這幾個資料結構還不熟悉,先參照我之前的文章吧。
#include <ngx_config.h>#include <ngx_core.h>#include <ngx_http.h>static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);static char *ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);/** * 處理nginx.conf中的配置命令解析 * 例如: * location /hello { * hello * } * 當使用者請求:http://127.0.0.1/hello的時候,請求會跳轉到hello這個配置上 * hello的命令列解析回呼函數:ngx_http_hello */static ngx_command_t ngx_http_hello_commands[] = {{ngx_string("hello"),NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,ngx_http_hello,NGX_HTTP_LOC_CONF_OFFSET,0,NULL},ngx_null_command};/** * 模組上下文 */static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, NULL, NULL, NULL,NULL, NULL, NULL, NULL };/** * 模組的定義 */ngx_module_t ngx_http_hello_module = {NGX_MODULE_V1,&ngx_http_hello_module_ctx,ngx_http_hello_commands,NGX_HTTP_MODULE,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING};/** * 命令解析的回呼函數 * 該函數中,主要擷取loc的配置,並且設定location中的回呼函數handler */static char *ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {ngx_http_core_loc_conf_t *clcf;clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);/* 設定回呼函數。當請求http://127.0.0.1/hello的時候,會調用此回呼函數 */clcf->handler = ngx_http_hello_handler;return NGX_CONF_OK;}/** * 模組回呼函數,輸出hello world */static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) {return NGX_HTTP_NOT_ALLOWED;}ngx_int_t rc = ngx_http_discard_request_body(r);if (rc != NGX_OK) {return rc;}ngx_str_t type = ngx_string("text/plain");ngx_str_t response = ngx_string("Hello World");r->headers_out.status = NGX_HTTP_OK;r->headers_out.content_length_n = response.len;r->headers_out.content_type = type;rc = ngx_http_send_header(r);if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {return rc;}ngx_buf_t *b;b = ngx_create_temp_buf(r->pool, response.len);if (b == NULL) {return NGX_HTTP_INTERNAL_SERVER_ERROR;}ngx_memcpy(b->pos, response.data, response.len);b->last = b->pos + response.len;b->last_buf = 1;ngx_chain_t out;out.buf = b;out.next = NULL;return ngx_http_output_filter(r, &out);}
修改Nginx.conf檔案 我們需要通過http://127.0.0.1/hello 就能訪問到我們自訂的hello模組。所以我們需要修改一下Nginx.conf檔案:
#ngx_http_hello_module.c location /hello { hello }
編譯Nginx源碼 編譯自訂的模組,需要加上:
--add_module=模組檔案夾
sudo ./configure --prefix=/Users/zhuli/Documents/code/soft/nginx --add-module=/Users/xxx/Documents/code/soft/nginx-1.13.1/extends/ngx_http_hello_modulesudo make && make install
編譯後,產生模組數組檔案:objs/ngx_modules.c 裡面就包含我們自訂的模組 (模組數組 *ngx_modules[] 中的值就是通過這個檔案初始化的;然後通過這個模組數組對每個模組進行初始化)
extern ngx_module_t ngx_http_limit_req_module;extern ngx_module_t ngx_http_geo_module;extern ngx_module_t ngx_http_map_module;extern ngx_module_t ngx_http_split_clients_module;extern ngx_module_t ngx_http_referer_module;extern ngx_module_t ngx_http_rewrite_module;extern ngx_module_t ngx_http_proxy_module;extern ngx_module_t ngx_http_fastcgi_module;extern ngx_module_t ngx_http_uwsgi_module;extern ngx_module_t ngx_http_scgi_module;extern ngx_module_t ngx_http_memcached_module;extern ngx_module_t ngx_http_empty_gif_module;extern ngx_module_t ngx_http_browser_module;extern ngx_module_t ngx_http_upstream_hash_module;extern ngx_module_t ngx_http_upstream_ip_hash_module;extern ngx_module_t ngx_http_upstream_least_conn_module;extern ngx_module_t ngx_http_upstream_keepalive_module;extern ngx_module_t ngx_http_upstream_zone_module;extern ngx_module_t ngx_http_hello_module;extern ngx_module_t ngx_http_write_filter_module;extern ngx_module_t ngx_http_header_filter_module;extern ngx_module_t ngx_http_chunked_filter_module;extern ngx_module_t ngx_http_range_header_filter_module;extern ngx_module_t ngx_http_gzip_filter_module;extern ngx_module_t ngx_http_postpone_filter_module;extern ngx_module_t ngx_http_ssi_filter_module;extern ngx_module_t ngx_http_charset_filter_module;extern ngx_module_t ngx_http_userid_filter_module;extern ngx_module_t ngx_http_headers_filter_module;extern ngx_module_t ngx_http_copy_filter_module;extern ngx_module_t ngx_http_range_body_filter_module;extern ngx_module_t ngx_http_not_modified_filter_module;
瀏覽器訪問 在瀏覽器中輸入http://127.0.0.1/hello 就能訪問我們自訂的hello模組了。