码迷,mamicode.com
首页 > 其他好文 > 详细

Nginx源码分析(5)

时间:2015-06-02 18:20:59      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

当需要为服务器增加一个自定义的扩展功能时,需要用到模块,相当于Nginx给开发者提供的一个模板范式。

比如现在实现一个书签收藏网站的signin功能,用Flask框架可以这样实现:

@app.route(‘/signin‘, methods=[‘GET‘, ‘POST‘])
def web_signin():
	if request.method == ‘GET‘:
		return redirect(url_for(‘web‘))
	if request.method == ‘POST‘:
		name = request.form.get(‘username‘, None)
		session[‘username‘] = name
		password = request.form.get(‘password‘, None)
		db = LinkDB()
		if name.strip()==‘‘ or password.strip()==‘‘:
			return redirect(url_for(‘web‘))
		if db.has_user(name, password):
			return render_template(‘page.html‘) 
		else:
			return ‘用户名或密码错误‘

它实现的功能就是解析用户GETPOST过来的数据,然后构造相应的响应。这和Nginx的handler模块所做的工作相似。

Nginx本身做的工作实际很少,当它接到一个HTTP请求时,它仅仅是通过查找配置文件将此次请求映射到一个location block,而此location中所配置的各个指令则会启动不同的模块去完成工作,因此模块可以看做Nginx真正的劳动工作者。下图表示一次请求和相应的完整过程。

技术分享

现在在浏览器中输入http://127.0.0.1/hello_world,让浏览器显示
hello_world, testing!!!怎么实现呢?这需要我们编写一个hello handler模块。

模块定义ngx_module_t

开发一个模块,需要定义一个ngx_module_t类型的变量来说明这个模块的信息。它定义在/nginx/src/core/ngx_config_file中。

struct ngx_module_s {
    ngx_uint_t            ctx_index;
    ngx_uint_t            index;
    ngx_uint_t            spare0;
    ngx_uint_t            spare1;
    ngx_uint_t            spare2;
    ngx_uint_t            spare3;
    ngx_uint_t            version;
    void                 *ctx;
    ngx_command_t        *commands;
    ngx_uint_t            type;

    ngx_int_t           (*init_master)(ngx_log_t *log);
    ngx_int_t           (*init_module)(ngx_cycle_t *cycle);
    ngx_int_t           (*init_process)(ngx_cycle_t *cycle);
    ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);
    void                (*exit_thread)(ngx_cycle_t *cycle);
    void                (*exit_process)(ngx_cycle_t *cycle);
    void                (*exit_master)(ngx_cycle_t *cycle);
    //...
};

hello模块定义如下:


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 };

模块的编写步骤是:

  • 这里是列表文本 编写模块基本结构。包括模块的定义,模块上下文结构,模块的配置结构等。
  • 实现handler的挂载函数。根据模块的需求选择正确的挂载方式。
  • 编写handler处理函数。模块的功能主要通过这个函数来完成。这是最关键的,hello模块的功能是简单返回一个字符串。在ngx_http_hello_world_handler中实现。
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);

    // 设置 request 的 header
    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));

    // 第 1 块缓冲区
    out[0].buf = b;
    out[0].next = &out[1];

    // 本模块中,缓冲区只需要写入数据,所以只设置 pos 和 last
    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));

    // 第 2 块缓冲区
    out[1].buf = b;
    out[1].next = NULL;

    // 本模块中,缓冲区只需要写入数据,所以只设置 pos 和 last
    b->pos = hlcf->output_words.data;
    b->last = hlcf->output_words.data + (hlcf->output_words.len);
    b->memory = 1; // 标示缓冲区是内存缓冲
    b->last_buf = 1; // 标示整个响应最后一个缓冲区,nginx会立即发送缓冲的所有数据

    // 设置 request 的 header
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = hlcf->output_words.len + sizeof("hello_world, ") - 1;

    // 发送 request
    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]);
}

配置和编译

在Nginx文件夹下


mkdir ngx_http_hello_world_module cd ngx_http_hello_world_module touch ngx_http_hello_world_module.c touch config

ngx_http_hello_world_module.c是主要的函数, config是配置文件。

在配置文件中加入

ngx_addon_name=ngx_http_hello_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"

这个config文件的内容就是告诉nginx的编译脚本,该如何进行编译。


./configure --add-module=/home/hy/Desktop/nginx/ngx_http_hello_world_module make make install

add-module后接上文中新建目录的路径。

使用

/usr/local/nginx/conf路径下的nginx.conf文件中加入

location /hello_world 
{
    hello_world testing!!!;
}

访问http://127.0.0.1/hello_world即可看见成功的页面。

技术分享

参考

http://blog.csdn.net/poechant/article/details/7627828

http://kb.cnblogs.com/page/98352/

http://wiki.nginx.org/3rdPartyModules

Nginx源码分析(5)

标签:

原文地址:http://my.oschina.net/lvyi/blog/423842

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!