首页 > 代码库 > nginx 学习(二) hello world 程序

nginx 学习(二) hello world 程序

hello wrold

1 本节目的

2实现步骤

  2.1config编写

  2.2模块代码实现

  2.3配置文件的编写

3将模块编译进nginx中


1本节的目的

本节用nginx来实现一个经典程序hello world,这个程序也是我们学任何编程语言时首先接触的程序,这个程序的目的是

初步了解nginx怎样嵌入第三方模块,也是学习nginx的HTTP模块的入门。

2实现步骤

nginx 提供了一种简单的方式将第三方模块嵌入nginx中:只需要三个步骤

步骤一:编写config

步骤二:实现模块的代码

步骤三:修改配置参数,将第三方模块编译到nginx中

下面我们来用最简单的hello world实例来讲这三个步骤的实现。

2.1config编写

config文件里面包含了三个参数,这三个参数如下:

ngx_addon_name:第三方模块名字,这个好像用处不大,一般设置为模块名称

HTTP_MODULES:HTPP模块名称

NGX_ADDON_SRCS:第三方模块源代码路径

下面是helloworld程序的config:

ngx_add_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"

2.2模块代码实现

下面来看怎样实现ngx_http_hello_module.c。

首先我们要定义两个函数:

static char* ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);
 ngx_http_hello

这个函数使用来分析配置文件中的参数,因为我们仅仅要输出hello world 所以我们用无参数的配置,即不许要解析参数的值,下一节我会详细将怎样分析配置参数
ngx_http_hello_handler

每个模块都有一个handler函数,这个函数负责对来自客户端请求的真正处理。这个函数的处理,既可以选择自己直接生成内容,也可以选择拒绝处理,由后续的handler去进行处理,或者是选择丢给后续的filter进行处理。

然后我们要定义三个结构体,这三个结构体是每个模块必不可缺少的结构体:

模块配置指令结构体:

static ngx_command_t ngx_http_hello_commands[] = {
    {
       ngx_string("test_hello"),
       NGX_HTTP_LOC_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
};
这里我们仅仅知道这三个结构体就行,后面我们会详细介绍。

然后看看nginx函数的实现:

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);
    clcf->handler = ngx_http_hello_handler;
    return NGX_CONF_OK;
}
这个函数主要是解析配置的参数,也可以设置模块的handler函数,这里我们没有解析配置参数,仅仅加载模块的handler函数。

再看真正处理用户请求的handler函数:

static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r)
{
    if (!(r->method & (NGX_HTTP_HEAD | NGX_HTTP_GET))) 
    {
       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/html");
    ngx_str_t response = ngx_string("hello world!");
    r->headers_out.content_type = type;
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;
    if (r->method == NGX_HTTP_HEAD)
    {
       return ngx_http_send_header(r);
    }
    
    ngx_buf_t* buf = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (buf == NULL)
    {
       return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    buf->pos = ngx_pcalloc(r->pool, response.len);
    buf->last = buf->pos + response.len;
    buf->last_buf = 1;
    buf->memory = 1;
    ngx_memcpy(buf->pos, response.data, response.len);
    
    ngx_chain_t out;
    out.buf = buf;
    out.next = NULL;
    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);
}
这个函数才是真正处理用户请求的函数,它在解析配置参数以后根据用户的请求作出相应处理,并把处理结果返回给用户。

这样一个简单的hello模块的代码就基本上完成了,其实主要就是上面的三个结构体的定义和handler函数的实现。

2.3配置文件的编写

我们实现一个功能是当我们在浏览其中输入:localhost/hello 按回车键时会看到:hello world!

在配置中应该有hello并且写在nginx.conf 的location:

   location /hello {
            test_hello ;//无参数的配置
     }
3将模块编译进nginx中

即安装第三方模块,如下:

./configure --prefix=/home/smtl/桌面/testNx/nginx --with-http_ssl_module --with-pcre=/home/smtl/下载/pcre-8.33 --with-zlib=/home/smtl/下载/zlib-1.2.8 --with-openssl=/home/smtl/下载/openssl-0.9.8o <span style="color:#FF0000;">--add-module=/home/smtl/桌面/testNx/nginx-1.0.15/my_hello_module</span>
(make , make install)

注意我们编写的代码所放的文件要放在和nginx源码所放的目录相同:nginx源码放在那个文件里,我们编写的代码的文件就放在那个文件里。

红色标记的部分是我们编写的代码ngx_htttp_hello_module.c所在的文件夹。

然后在浏览器里面输入:localhost/hello。

浏览器输出hello world


程序源代码:



#include <ngx_config.h>
#include <ngx_http.h>
#include <ngx_core.h>

static char* ngx_http_hello(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);

static ngx_command_t ngx_http_hello_commands[] = {
    {
       ngx_string("test_hello"),
       NGX_HTTP_LOC_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,
};

/* static 加上static有错误 */
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
};

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);
    clcf->handler = ngx_http_hello_handler;
    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r)
{
    if (!(r->method & (NGX_HTTP_HEAD | NGX_HTTP_GET))) 
    {
       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/html");
    ngx_str_t response = ngx_string("hello world!");
    r->headers_out.content_type = type;
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = response.len;
    if (r->method == NGX_HTTP_HEAD)
    {
       return ngx_http_send_header(r);
    }
    
    ngx_buf_t* buf = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
    if (buf == NULL)
    {
       return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    buf->pos = ngx_pcalloc(r->pool, response.len);
    buf->last = buf->pos + response.len;
    buf->last_buf = 1;
    buf->memory = 1;
    ngx_memcpy(buf->pos, response.data, response.len);
    
    ngx_chain_t out;
    out.buf = buf;
    out.next = NULL;
    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);
}














nginx 学习(二) hello world 程序