解剖Nginx·模組開發篇(1)跑起你的 Hello World 模組!
解剖Nginx·模組開發篇(1)跑起你的 Hello World 模組!
- 作者:柳大·Poechant(鍾超)
- 郵箱:zhongchao.ustc#gmail.com(# -> @)
- 部落格:Blog.CSDN.net/Poechant
- 日期:June 2nd, 2012
1 學習 Nginx 模組開發需要有哪些準備?
需要的預備知識不多,有如下幾點:
- 有過一些 C 語言的程式設計經歷;
- 知道 Nginx 是幹嘛的,並有過編寫或改寫 Nginx 的配置檔案的經歷。
OK,就這兩點就夠了 :)
好了,那就開始吧~
2 我們的 HelloWorld 的目標是什麼?
我們的目標,就是你在瀏覽器裡輸入http://localhost/hello_world
時,顯示:
hello world
當然,為了能夠更加自定義一些,我們嘗試在hello world
後面再顯示一個字串,比如:
hello world, Poechant
那麼我們的配置檔案看起來是什麼樣的呢?
http {
include mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.php index.html index.htm;
}
location /hello_world {
hello_world Poechant;
}
}
}
是的,很簡單吧,唯一特別的部分,就是:
location /hello_world {
hello_world Poechant;
}
3 開工
3.1 目錄結構
首先要明確,我們的檔案和目錄結構:
ngx_http_hello_world_module
|_____________ngx_http_hello_world_module.c
|_____________config
其中ngx_http_hello_world_module.c
是模組的 C 原始碼檔案,config
是模組的配置檔案。
3.2 ngx_http_hello_world_module.c
定義一個結構體:
typedef struct {
ngx_str_t output_words;
} ngx_http_hello_world_loc_conf_t;
定義三個變數:
// Structure for the HelloWorld command
static ngx_command_t ngx_http_hello_world_commands[] = {
{
ngx_string("hello_world"), // The command name
NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_http_hello_world, // The command handler
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_world_loc_conf_t, output_words),
NULL
},
ngx_null_command
};
// Structure for the HelloWorld context
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ngx_http_hello_world_create_loc_conf,
ngx_http_hello_world_merge_loc_conf
};
// Structure for the HelloWorld module, the most important thing
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,
ngx_http_hello_world_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
定義三個函式:
static char* ngx_http_hello_world(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
static void* ngx_http_hello_world_create_loc_conf(ngx_conf_t* cf)
static char* ngx_http_hello_world_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child)
完整的程式如下:
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
ngx_str_t output_words;
} ngx_http_hello_world_loc_conf_t;
// To process HelloWorld command arguments
static char* ngx_http_hello_world(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
// Allocate memory for HelloWorld command
static void* ngx_http_hello_world_create_loc_conf(ngx_conf_t* cf);
// Copy HelloWorld argument to another place
static char* ngx_http_hello_world_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child);
// Structure for the HelloWorld command
static ngx_command_t ngx_http_hello_world_commands[] = {
{
ngx_string("hello_world"), // The command name
NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
ngx_http_hello_world, // The command handler
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_hello_world_loc_conf_t, output_words),
NULL
},
ngx_null_command
};
// Structure for the HelloWorld context
static ngx_http_module_t ngx_http_hello_world_module_ctx = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ngx_http_hello_world_create_loc_conf,
ngx_http_hello_world_merge_loc_conf
};
// Structure for the HelloWorld module, the most important thing
ngx_module_t ngx_http_hello_world_module = {
NGX_MODULE_V1,
&ngx_http_hello_world_module_ctx,
ngx_http_hello_world_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING
};
static ngx_int_t ngx_http_hello_world_handler(ngx_http_request_t* r) {
ngx_int_t rc;
ngx_buf_t* b;
ngx_chain_t out[2];
ngx_http_hello_world_loc_conf_t* hlcf;
hlcf = ngx_http_get_module_loc_conf(r, ngx_http_hello_world_module);
r->headers_out.content_type.len = sizeof("text/plain") - 1;
r->headers_out.content_type.data = (u_char*)"text/plain";
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
out[0].buf = b;
out[0].next = &out[1];
b->pos = (u_char*)"hello_world, ";
b->last = b->pos + sizeof("hello_world, ") - 1;
b->memory = 1;
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
out[1].buf = b;
out[1].next = NULL;
b->pos = hlcf->output_words.data;
b->last = hlcf->output_words.data + (hlcf->output_words.len);
b->memory = 1;
b->last_buf = 1;
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = hlcf->output_words.len + sizeof("hello_world, ") - 1;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
return ngx_http_output_filter(r, &out[0]);
}
static void* ngx_http_hello_world_create_loc_conf(ngx_conf_t* cf) {
ngx_http_hello_world_loc_conf_t* conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_world_loc_conf_t));
if (conf == NULL) {
return NGX_CONF_ERROR;
}
conf->output_words.len = 0;
conf->output_words.data = NULL;
return conf;
}
static char* ngx_http_hello_world_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child) {
ngx_http_hello_world_loc_conf_t* prev = parent;
ngx_http_hello_world_loc_conf_t* conf = child;
ngx_conf_merge_str_value(conf->output_words, prev->output_words, "Nginx");
return NGX_CONF_OK;
}
static char* ngx_http_hello_world(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);
clcf->handler = ngx_http_hello_world_handler;
ngx_conf_set_str_slot(cf, cmd, conf);
return NGX_CONF_OK;
}
3.3 config
ngx_addon_name=ngx_http_hello_world_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_world_module.c"
3.4 編寫配置檔案
最開始已經展示過了,就是它。
3.5 編譯你的模組
$ ./configure --add-module=/your/module/path/ngx_http_hello_world_module
make
如果沒有任何錯誤提示的話,那麼恭喜你,你的模組編譯通過了!
然後執行 Nginx。如果沒有任何錯誤提示的話,再次恭喜你,你的模組已經被正常載入執行了!
3.6 測試你的模組
http://localhost/hello_world
你應該會看到:
hello_world, Poechant
這個簡單模組的詳細解釋,在該系列博文的第二、三、四篇中。
4 恐怕我還是要說一些“非程式碼”
一般來說,剛入門做某件事情的時候,我們不大想聽廢話,希望趕緊開始上手幹活,否則會覺得很空洞。這也是為什麼我一開始就上了一個例子,並給出程式碼。但是還是要了解一些“空話”,才有助於理解。
Nginx 處理請求的過程,是在請求收到後定位到配置檔案中描述的相應 location,然後由 handler 生成 response,再由 filter 進行處理。所以模組開發,可以是 handler 模組開發,也可以是 filter 模組開發(當然還有其他型別的模組)。
5 推薦一些參考
- Emiller’s Guide to Nginx Module Development
- Emiller’s Advanced Topics in Nginx Module Development
- crk_world的部落格
- Ngx Deve Kit
- Emiller’s Guide To Nginx Module Development 中文版
- Nginx & OpenResty
- CodingLabs-Nginx模組開發入門
-
轉載請註明來自柳大的CSDN部落格:Blog.CSDN.net/Poechant
-
相關文章
- nginx事件模組 -- 第二篇Nginx事件
- nginx事件模組-- 第四篇Nginx事件
- nginx事件模組 -- 第三篇Nginx事件
- Nginx常用的模組Nginx
- nginx事件模組 -- 第一篇Nginx事件
- 使用typescript開發angular模組(編寫模組)TypeScriptAngular
- 為 Nginx 新增模組Nginx
- Nginx 新增 lua 模組Nginx
- nginx事件模組 -- 第五篇 epoll addNginx事件
- 一篇文章說透Nginx的rewrite模組Nginx
- nginx學習之模組Nginx
- 模組化開發(二)
- 前端模組化開發前端
- Nginx的HTTP模組與Stream模組:區別與應用場景NginxHTTP
- Tengine新增nginx upstream模組的使用Nginx
- 序列化模組,隨機數模組,os模組,sys模組,hashlib模組隨機
- Laravel-Module 模組開發一:評論模組實現Laravel
- Js模組化開發的理解JS
- nginx事件模組 -- 第七篇 建立連線Nginx事件
- Nginx安裝nginx-rtmp-module模組Nginx
- Nginx使用SSL模組配置httpsNginxHTTP
- android IM模組-語音-錄製篇1Android
- python 模組:itsdangerous 模組Python
- path模組 fs模組
- Python模組:time模組Python
- 淺談模組化開發
- 模組化開發淺析
- 聊聊前端模組化開發前端
- ModStartCMS模組開發介紹
- Nginx的ngx_http_fastcgi_module模組NginxHTTPAST
- day18:json模組&time模組&zipfile模組JSON
- ruby 中的 forwardable 模組(1)Forward
- ??Java開發者的Python快速進修指南:自定義模組及常用模組JavaPython
- Python模組之urllib模組Python
- python模組之collections模組Python
- CommonJS模組 和 ECMAScript模組JS
- nginx使用熱部署新增新模組Nginx熱部署
- Nginx使用Lua模組實現WAFNginx
- Nginx 高階篇(八)ab 壓力測試即 nginx 的效能統計模組Nginx