对于一些访问量特别大,业务逻辑也相对简单的Web调用来说,通过一个nginx module来实现是一种比较好的优化方法。实现一个nginx module实际上比较简单。
1. nginx 配置添加
./configure --add-module=/path/to/module1/source
2. 添加 /path/to/module1/source/config 文件,内容
ngx_addon_name=ngx_http_hello_module HTTP_MODULES="$HTTP_MODULES ngx_http_hello_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_module.c" CORE_LIBS="$CORE_LIBS -lfoo"
最后一行如果没有使用其他library, 可以去掉
3. 源代码 /path/to/module1/source/ngx_http_hello_module.c, 主要的业务逻辑在make_http_get_body 中完善。典型的hello world源代码如下
#include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> #define OUT_BUFSIZE 256 static char *ngx_http_hello_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_foo_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_http_hello_process_init(ngx_cycle_t *cycle); static void ngx_http_hello_process_exit(ngx_cycle_t *cycle); static ngx_int_t make_http_header(ngx_http_request_t *r); static ngx_int_t make_http_get_body(ngx_http_request_t *r, char *out_buf); static char g_foo_settings[64] = {0}; /* Commands */ static ngx_command_t ngx_http_hello_commands[] = { { ngx_string("ngx_hello_module"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_http_hello_set, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, { ngx_string("hello"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_foo_set, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, ngx_null_command }; static ngx_http_module_t ngx_http_hello_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ NULL, /* create location configuration */ NULL /* merge location configuration */ }; /* hook */ ngx_module_t ngx_http_hello_module = { NGX_MODULE_V1, &ngx_http_hello_module_ctx, /* module context */ ngx_http_hello_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ ngx_http_hello_process_init, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ ngx_http_hello_process_exit, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; /* setting header for no-cache */ static ngx_int_t make_http_header(ngx_http_request_t *r){ ngx_uint_t i; ngx_table_elt_t *cc, **ccp; r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; ccp = r->headers_out.cache_control.elts; if (ccp == NULL) { if (ngx_array_init(&r->headers_out.cache_control, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK) { return NGX_ERROR; } ccp = ngx_array_push(&r->headers_out.cache_control); if (ccp == NULL) { return NGX_ERROR; } cc = ngx_list_push(&r->headers_out.headers); if (cc == NULL) { return NGX_ERROR; } cc->hash = 1; cc->key.len = sizeof("Cache-Control") - 1; cc->key.data = (u_char *) "Cache-Control"; *ccp = cc; } else { for (i = 1; i < r->headers_out.cache_control.nelts; i++) { ccp[i]->hash = 0; } cc = ccp[0]; } cc->value.len = sizeof("no-cache") - 1; cc->value.data = (u_char *) "no-cache"; return NGX_OK; } static ngx_int_t make_http_get_body(ngx_http_request_t *r, char *out_buf){ char *qs_start = (char *)r->args_start; char *qs_end = (char *)r->uri_end; char uri[128] = {0}; char *id; if (qs_start == NULL || qs_end == NULL){ return NGX_HTTP_BAD_REQUEST; } if ((memcmp(qs_start, "id=", 3) == 0)){ id = qs_start + 3; *qs_end = '\0'; }else{ return NGX_HTTP_BAD_REQUEST; } snprintf(uri, r->uri.len + 1, "%s", r->uri.data); sprintf(out_buf, "Author: http://timyang.net/\nconfig=%s\nid=%snuri=%s\nret=%lx\n", g_foo_settings, id, uri, ngx_random()); return NGX_OK; } static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t out; /* Http Output Buffer */ char out_buf[OUT_BUFSIZE] = {0}; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK && rc != NGX_AGAIN) { return rc; } /* make http header */ rc = make_http_header(r); if (rc != NGX_OK) { return rc; } if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; return ngx_http_send_header(r); } else if (r->method == NGX_HTTP_GET) { /* make http get body buffer */ rc = make_http_get_body(r, out_buf); if (rc != NGX_OK) { return rc; } } else { return NGX_HTTP_NOT_ALLOWED; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } out.buf = b; out.next = NULL; b->pos = (u_char *)out_buf; b->last = (u_char *)out_buf + strlen(out_buf); b->memory = 1; b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = strlen(out_buf); 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); } static char * ngx_http_hello_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); /* register hanlder */ clcf->handler = ngx_http_hello_handler; return NGX_CONF_OK; } static char * ngx_http_foo_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *value = cf->args->elts; memcpy(g_foo_settings, value[1].data, value[1].len); g_foo_settings[value[1].len] = '�'; return NGX_CONF_OK; } static ngx_int_t ngx_http_hello_process_init(ngx_cycle_t *cycle) { // do some init here return NGX_OK; } static void ngx_http_hello_process_exit(ngx_cycle_t *cycle) { return; }
4. 配置文件 nginx.conf
location /hello { ngx_hello_module; hello 1234; }
5. 访问 http://localhost/hello?id=1
也可参考更详细的英文说明:
Emiller’s Guide To Nginx Module Development
试验了你提供的nginx module的例子,编译通过了,但是最后访问http://localhost/hello,报400 Bad Request的错,请教一下什么原因?
编译成功,访问报400 Bad Request
注意看了源代码,最终访问的地址是:
http://localhost/hello?id=6
参见源码123行
请问213行引号里的字符是啥??
我们在编写了 15 个产品级的 nginx 开源模块之后,发出的感慨其实是“实现一个nginx module实际上很不简单”,呵呵。
当然,如果需要编写的 nginx 模块只是进行纯粹的 CPU 计算,确实还是很简单的,但在真实世界中这样的模块并非总是那么有趣
在 nginx 模块开发中经常面临的挑战就是必须进行非阻塞的 socket 通信
依葫芦画瓢 能勉强写些模块出来
Amazing! Tһis blog looks exactly lіke mʏ old one!
It’s on a entirely different subject Ƅut it һas pretty mսch the same pаge layout andd design.
Superb choice οf colors!
Does your website have a contact page? I’m having trouble locating it but, I’d like
tto send you an email. I’ve got some ideas for your blog
you might be interested in hearing. Either way, great blog and I look orward to seeing it grow over time.
Hello Dear, are you in fact visiting this web page daily, if so afterward you
will definitely get good experience.
С уважением,
Старший менеджер Гребнева Анисья Артуровна
Writing an nginx module can be a useful optimization method for handling high-traffic web calls with simple business logic. Despite what one might think, implementing an nginx module is relatively straightforward.
Thanks for sharing this module with the Best fence contractor in Marietta. It’s pretty simple and useful.
Check out this amazing module that’s perfect for http://www.riversidedrywall.com and anyone that is eager to dive deep into a specific topic. Cheers!