初识Nginx

1.为什么选择Nginx

Nginx是当前最流行的Web服务器之一,与Apache相比,Nginx在高并发情况下具有巨大的性能优势。

Nginx具有高扩展性,高可靠性,低内存消耗等特点,并且Nginx拥有无数官方功能模块,第三方功能模块,这些功能模块可以叠加以实现更加强大/复杂的功能。

选择Nginx的核心理由是它能在支持高并发请求的同时保持高效的服务。

 

2.Nginx的安装与运行Nginx官方下载地址:http://nginx.org/en/download.html

解压:$ tar -zxvf nginx-1.4.4.tar.gz

进入nginx目录,执行如下命令:

$ ./configure
$ make
$ make install

启动Nginx:$ /usr/local/nginx/sbin/nginx

检测Nginx是否成功运行:打开http://localhost/,看是否有Nginx欢迎界面。

停止Nginx服务:/usr/local/nginx/sbin/nginx -s stop

 

3.开发一个简单的HTTP模块-Hello World

Nginx提供了一种简单的方式将第三方模块编译到Nginx中。

首先把源代码文件全部放到一个目录中:

my_test_module/

├── config

└── ngx_http_mytest_module.c

configure用于通知Nginx如何编译本模块,而且必须命名为configure。configure文件其实是一个可执行shell脚本,需要定义以下3个变量:

ngx_addon_name:仅在configure执行时使用,一般设置为模块名称。
HTTP_MODULES:保存所有的HTTP模块名称,每个HTTP模块间由空格相连。
NGX_ADDON_SRCS:用于制定新增模块的源代码,多个待编译的源代码间以空格相连。

这里configure内容如下:

ngx_addon_name=ngx_http_mytest_module
HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"

 这里ngx_http_mytest_module.c内容如下:

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

static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);

static ngx_command_t  ngx_http_mytest_commands[] =
{

    {
        ngx_string("mytest"),
        NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
        ngx_http_mytest,
        NGX_HTTP_LOC_CONF_OFFSET,
        0,
        NULL
    },

    ngx_null_command
};

static ngx_http_module_t  ngx_http_mytest_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 */
};

ngx_module_t  ngx_http_mytest_module =
{
    NGX_MODULE_V1,
    &ngx_http_mytest_module_ctx,           /* module context */
    ngx_http_mytest_commands,              /* module directives */
    NGX_HTTP_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};


static char *
ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_loc_conf_t  *clcf;

    //首先找到mytest配置项所属的配置块,clcf貌似是location块内的数据
//结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说在每个
//http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    //http框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果
//请求的主机域名、URI与mytest配置项所在的配置块相匹配,就将调用我们
//实现的ngx_http_mytest_handler方法处理这个请求
    clcf->handler = ngx_http_mytest_handler;

    return NGX_CONF_OK;
}


static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
    //必须是GET或者HEAD方法,否则返回405 Not Allowed
    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;
    }

    //设置返回的Content-Type。注意,ngx_str_t有一个很方便的初始化宏
//ngx_string,它可以把ngx_str_t的data和len成员都设置好
    ngx_str_t type = ngx_string("text/plain");
    //返回的包体内容
    ngx_str_t response = ngx_string("Hello World!");
    //设置返回状态码
    r->headers_out.status = NGX_HTTP_OK;
    //响应包是有包体内容的,所以需要设置Content-Length长度
    r->headers_out.content_length_n = response.len;
    //设置Content-Type
    r->headers_out.content_type = type;

    //发送http头部
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
    {
        return rc;
    }

    //构造ngx_buf_t结构准备发送包体
    ngx_buf_t                 *b;
    b = ngx_create_temp_buf(r->pool, response.len);
    if (b == NULL)
    {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    //将Hello World拷贝到ngx_buf_t指向的内存中
    ngx_memcpy(b->pos, response.data, response.len);
    //注意,一定要设置好last指针
    b->last = b->pos + response.len;
    //声明这是最后一块缓冲区
    b->last_buf = 1;

    //构造发送时的ngx_chain_t结构体
    ngx_chain_t		out;
    //赋值ngx_buf_t
    out.buf = b;
    //设置next为NULL
    out.next = NULL;

    //最后一步发送包体,http框架会调用ngx_http_finalize_request方法
//结束请求
    return ngx_http_output_filter(r, &out);
}

修改配置文件:$ vim //usr/local/nginx/conf/nginx.conf,增加下面的配置:

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 /test {
            mytest;
        }
    }
}

编译安装模块:

./configure --prefix=/usr/local/nginx(指定安装部署后的根目录) --add-module=/home/luhaiyang/ngxdev/ngx_http_mytest(新模块存放目录)  
make  
sudo make install 

 测试模块:$ curl -i http://localhost/test

HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Mon, 02 Dec 2013 09:35:50 GMT
Content-Type: text/plain
Content-Length: 12
Connection: keep-alive

Hello World!

 

阅读《深入理解Nginx》,简单知道了Nginx的基本概念,并参照书籍配置了一个静态Web服务器。在我的学习习惯里,我喜欢先赶紧实现一个简单的例子,这样对于新事物有一个大概的总体的了解,知道它到底是什么,能干什么,然后再继续深入挖掘理解。

最近与基友ZK讨论学习习惯的问题,他这段之间在接受java培训,与我讲述了他的烦恼。他认为只有学习掌握好了当前内容才能继续下一阶段的学习,所以不能理解他的项目经理提前讲解后面的知识章节,然后我跟他分享了我的学习方法。我认为这是两种不同的学习习惯,只有适合自己的才是最好的。

 

参考资料:《深入理解Nginx》

 

posted @ 2013-12-02 17:37  七年之后  阅读(304)  评论(0编辑  收藏  举报