nginx 编写简单HTTP模块以及nginx http handler的hello world示例编写

编写nginx http handler模块以便开发自己模块,本文提供hello编写到编译的详细步骤 , 文章最后提供整个示例代码

编写http handler模块的几个组成部分讲解:

1、ngx_command_t

示例:

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

在nginx.conf 中编写的配置项 mytest 来说, nginx 首先会遍历所有的模块(modules),而对于每个模块, 会遍历他所对应的ngx_command_t 数组, 试图找到关于我们的配置项mytest 的解析方式。
command中用于处理配置项参数的set 方法,函数名格式写法ngx_http_xxxxx,如下所示:

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

关于ngx_http_conf_get_module_loc_conf 的定义可以参考: http://lxr.nginx.org/source/src/http/ngx_http_config.h#0065 本质: 就是设置ngx_http_mytest_handler, 匹配项被选中的时候, 应该如何解析。

ngx_command_t的定义,位于src/core/ngx_conf_file.h中。

struct ngx_command_s {
    ngx_str_t             name;
    ngx_uint_t            type;
    char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
    ngx_uint_t            conf;
    ngx_uint_t            offset;
    void                 *post;
};

name: 配置指令的名称。

type: 该配置的类型,其实更准确一点说,是该配置指令属性的集合。nginx提供了很多预定义的属性值(一些宏定义),通过逻辑或运算符可组合在一起,形成对这个配置指令的详细的说明。下面列出可在这里使用的预定义属性值及说明。

  • NGX_CONF_NOARGS:配置指令不接受任何参数。

  • NGX_CONF_TAKE1:配置指令接受1个参数。

  • NGX_CONF_TAKE2:配置指令接受2个参数。

  • NGX_CONF_TAKE3:配置指令接受3个参数。

  • NGX_CONF_TAKE4:配置指令接受4个参数。

  • NGX_CONF_TAKE5:配置指令接受5个参数。

  • NGX_CONF_TAKE6:配置指令接受6个参数。

  • NGX_CONF_TAKE7:配置指令接受7个参数。

可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数。那么就是NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。如果写上面三个属性在一起,你觉得麻烦,那么没有关系,nginx提供了一些定义,使用起来更简洁。

  • NGX_CONF_TAKE12:配置指令接受1个或者2个参数。

  • NGX_CONF_TAKE13:配置指令接受1个或者3个参数。

  • NGX_CONF_TAKE23:配置指令接受2个或者3个参数。

  • NGX_CONF_TAKE123:配置指令接受1个或者2个或者3参数。

  • NGX_CONF_TAKE1234:配置指令接受1个或者2个或者3个或者4个参数。

  • NGX_CONF_1MORE:配置指令接受至少一个参数。

  • NGX_CONF_2MORE:配置指令接受至少两个参数。

  • NGX_CONF_MULTI: 配置指令可以接受多个参数,即个数不定。

  • NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块。也就是一对大括号括起来的内容。里面可以再包括很多的配置指令。比如常见的server指令就是这个属性的。

  • NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”,最终会被转成bool值。

  • NGX_CONF_ANY:配置指令可以接受的任意的参数值。一个或者多个,或者”on”或者”off”,或者是配置块。 最后要说明的是,无论如何,nginx的配置指令的参数个数不可以超过NGX_CONF_MAX_ARGS个。目前这个值被定义为8,也就是不能超过8个参数值。

下面介绍一组说明配置指令可以出现的位置的属性。

  • NGX_DIRECT_CONF:可以出现在配置文件中最外层。例如已经提供的配置指令daemon,master_process等。

  • NGX_MAIN_CONF: http、mail、events、error_log等。

  • NGX_ANY_CONF: 该配置指令可以出现在任意配置级别上。 对于我们编写的大多数模块而言,都是在处理http相关的事情,也就是所谓的都是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置。

  • NGX_HTTP_MAIN_CONF: 可以直接出现在http配置指令里。

  • NGX_HTTP_SRV_CONF: 可以出现在http里面的server配置指令里。

  • NGX_HTTP_LOC_CONF: 可以出现在http server块里面的location配置指令里。

  • NGX_HTTP_UPS_CONF: 可以出现在http里面的upstream配置指令里。

  • NGX_HTTP_SIF_CONF: 可以出现在http里面的server配置指令里的if语句所在的block中。

  • NGX_HTTP_LMT_CONF: 可以出现在http里面的limit_except指令的block中。

  • NGX_HTTP_LIF_CONF: 可以出现在http server块里面的location配置指令里的if语句所在的block中。

set: 这是一个函数指针,当nginx在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。来看一下这个函数指针要求的函数原型。

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

2、定义ngx_http_module_t 接口

这部分的代码, 是用于http框架的, 相当于http框架的回掉函数, 由于这里并不需要框架做任何操作,格式ngx_http_xxxxx_module_ctx。

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

3、ngx_module_t模块的定义

示例: 格式ngx_http_xxxx_module

只需要简单的设置3个项目: ctx(指向模块的上下文), commands, type(模块类型)

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

来参考一下深入理解nginx书中对http模块数据结构的理解:

定义 HTTP 模块方式很简单,例如:
ngx_module_t ngx_http_mytest_module;
其中,ngx_module_t 是一个 Nginx 模块的数据结构(详见 8.2 节)。下面来分析一下
Nginx 模块中所有的成员,如下所示:
typedef struct ngx_module_s ngx_module_t;
struct ngx_module_s {
/* 下面的 ctx_index、index、spare0、spare1、spare2、spare3、version 变量不需要在定义时赋值,
可以用 Nginx 准备好的宏 NGX_MODULE_V1 来定义,它已经定义好了这 7 个值。
#define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1
对于一类模块(由下面的 type 成员决定类别)而言,ctx_index 表示当前模块在这类模块中的序号。这
个成员常常是由管理这类模块的一个 Nginx 核心模块设置的,对于所有的 HTTP 模块而言,ctx_index 是由核心模
块 ngx_http_module 设置的。ctx_index 非常重要,Nginx 的模块化设计非常依赖于各个模块的顺序,它们既用
于表达优先级,也用于表明每个模块的位置,借以帮助 Nginx 框架快速获得某个模块的数据(HTTP 框架设置 ctx_
index 的过程参见 10.7 节)*/
ngx_uint_t ctx_index;
/*index 表示当前模块在 ngx_modules 数组中的序号。注意,ctx_index 表示的是当前模块在一类模
块中的序号,而 index 表示当前模块在所有模块中的序号,它同样关键。Nginx 启动时会根据 ngx_modules 数组
设置各模块的 index 值。例如:
ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = ngx_max_module++;
}
*/
ngx_uint_t index;
//spare 系列的保留变量,暂未使用
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
// 模块的版本,便于将来的扩展。目前只有一种,默认为 1
ngx_uint_t version;
/*ctx 用于指向一类模块的上下文结构体,为什么需要 ctx 呢?因为前面说过,Nginx 模块有许多种类,
不同类模块之间的功能差别很大。例如,事件类型的模块主要处理 I/O 事件相关的功能,HTTP 类型的模块主要处理
HTTP 应用层的功能。这样,每个模块都有了自己的特性,而 ctx 将会指向特定类型模块的公共接口。例如,在 HTTP
模块中,ctx 需要指向 ngx_http_module_t 结构体 */
void *ctx;
//commands 将处理 nginx.conf 中的配置项,详见第 4 章
ngx_command_t *commands;
/*type 表示该模块的类型,它与 ctx 指针是紧密相关的。在官方 Nginx 中,它的取值范围是以下 5 种 :
NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_MAIL_MODULE。这
5 种模块间的关系参考图 8-2。实际上,还可以自定义新的模块类型 */
ngx_uint_t type;
/* 在 Nginx 的启动、停止过程中,以下 7 个函数指针表示有 7 个执行点会分别调用这 7 种方法(参见
8.4 节~ 8.6 节)。对于任一个方法而言,如果不需要 Nginx 在某个时刻执行它,那么简单地把它设为 NULL 空指针
即可 */
/* 虽然从字面上理解应当在 master 进程启动时回调 init_master,但到目前为止,框架代码从来不会
调用它,因此,可将 init_master 设为 NULL */
ngx_int_t (*init_master)(ngx_log_t *log);
/*init_module 回调方法在初始化所有模块时被调用。在 master/worker 模式下,这个阶段将在启动
worker 子进程前完成 */
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
/* init_process 回调方法在正常服务前被调用。在 master/worker 模式下,多个 worker 子进程已经产
生,在每个 worker 进程的初始化过程会调用所有模块的 init_process 函数 */
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
/* 由于 Nginx 暂不支持多线程模式,所以 init_thread 在框架代码中没有被调用过,设为 NULL*/
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
// 同上,exit_thread 也不支持,设为 NULL
void (*exit_thread)(ngx_cycle_t *cycle);
/* exit_process 回调方法在服务停止前调用。在 master/worker 模式下,worker 进程会在退出前调用它 */
void (*exit_process)(ngx_cycle_t *cycle);
// exit_master 回调方法将在 master 进程退出前被调用
void (*exit_master)(ngx_cycle_t *cycle);
/* 以下 8 个 spare_hook 变量也是保留字段,目前没有使用,但可用 Nginx 提供的 NGX_MODULE_V1_
PADDING 宏来填充。看一下该宏的定义:#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0*/
uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
第 3 章 开发一个简单的 HTTP 模块 87
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};
  1. 定义一个 HTTP 模块时,务必把 type 字段设为 NGX_HTTP_MODULE。

  2. 对于下列回调方法 :init_module、init_process、exit_process、exit_master,调用它们的 是 Nginx 的框架代码。换句话说,这 4 个回调方法与 HTTP 框架无关,即使 nginx.conf 中没 有配置 http {...} 这种开启 HTTP 功能的配置项,这些回调方法仍然会被调用。因此,通常 开发 HTTP 模块时都把它们设为 NULL 空指针。这样,当 Nginx 不作为 Web 服务器使用时, 不会执行 HTTP 模块的任何代码。

  3. 定义 HTTP 模块时,最重要的是要设置 ctx 和 commands 这两个成员。对于 HTTP 类型 的模块来说,ngx_module_t 中的 ctx 指针必须指向 ngx_http_module_t 接口(HTTP 框架的要 求)。下面先来分析 ngx_http_module_t 结构体的成员。

  4. HTTP 框架在读取、重载配置文件时定义了由 ngx_http_module_t 接口描述的 8 个阶段, HTTP 框架在启动过程中会在每个阶段中调用 ngx_http_module_t 中相应的方法。当然,如果 ngx_http_module_t 中的某个回调方法设为 NULL 空指针,那么 HTTP 框架是不会调用它的。

4.编写config文件,编译代码的时候用

config文件和编写c文件放在同一个文件下:比如我放在:

[root@hadoop2 nginx-1.13.8]# pwd
/root/nginx-1.13.8
[root@hadoop2 nginx-1.13.8]# cd mytesthttp/
[root@hadoop2 mytesthttp]# ll
total 16
-rw-r--r-- 1 root root  163 Jan 18 09:56 config
-rw-r--r-- 1 root root 8915 Jan 18 15:52 ngx_http_mytest_module.c
[root@hadoop2 mytesthttp]#

其中config文件内容基本下面的形式:

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_addon_dir 这个值是执行configure 时候添加的选线--add-module提供的:--add-module=/root/nginx-1.13.8/mytesthttp

执行nginx目录下configure生成makefile,--prefix=/root/nginx-1.13.8/bin提供nginx的安装路径,随便设置成你自己的想安装到的目录都是可以的。

./configure \
  --prefix=/root/nginx-1.13.8/bin  \
  --user=root\
  --group=root\
  --add-module=/root/nginx-1.13.8/mytesthttp  \
  --with-http_stub_status_module \
  --with-http_flv_module \
  --with-http_stub_status_module \
  --with-http_gzip_static_module \
  --with-http_gunzip_module \
  --with-pcre \
  --with-debug

5.配置nginx配置文件nginx.conf。一般nginx的conf文件在安装路径目录下(--prefix提供的那个路径):

添加内容参考如下:

server {
        listen       8017;
        server_name  localhost;

        access_log  logs/get.log  main;
        #access_log off;

        location / 
        {
            root   html;
            index  index.html index.htm;
        }

        location /hello  
        {
    
            mytest;
        }
       error_page   500 502 503 504  /50x.html;
       location = /50x.html 
       {
            root   html;
       }
    }

访问示例:

http://192.168.0.153:8017/hello/mytest

整体code参考:(结合文章理解)

#include 
#include 
#include 

#define PB_SIZE (1024 * 2)
#define CONTENT_TYPE "application/json;charset=GB2312"


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 void ngx_http_read_client_request_body_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;

    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

    clcf->handler = ngx_http_mytest_handler;

    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
    static char uri[PB_SIZE];
    static char decode[PB_SIZE];
    static char args[PB_SIZE];
    
    char* src;
    char* dst;
    int status=NGX_HTTP_OK;
    //int reply_len=0;
    //char *reply=0;
    ngx_int_t     rc;
    ngx_chain_t   out;
    
    //post handle
    if ((r->method & (NGX_HTTP_POST|NGX_HTTP_HEAD))) 
    {
        //get body
        rc = ngx_http_read_client_request_body(r, ngx_http_read_client_request_body_handler);
        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }
        return NGX_DONE;
    }
    //get handle
    else if ((r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) 
    {
        //get uri
        if (r->uri.len>=PB_SIZE)
            return NGX_HTTP_NOT_ALLOWED;    
        ngx_memcpy(uri,r->uri.data,r->uri.len);
        uri[r->uri.len]=0;
        src = uri;
        dst = decode;
        ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->uri.len, 0);
        ngx_memcpy(uri,decode,dst - decode);
        uri[dst - decode] = '\0';
    
        //get args
        if (r->args.len>=PB_SIZE)
            return NGX_HTTP_NOT_ALLOWED;
        ngx_memcpy(args,r->args.data,r->args.len);
        args[r->args.len]=0;
        src = args;
        dst =decode;
        ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->args.len, 0);
        ngx_memcpy(args,decode,dst - decode);
        args[dst - decode] = '\0';

        //reply=request(uri,args,&status,&reply_len);
        ngx_str_t response = ngx_string("Hello World!");

        if (status!=NGX_HTTP_OK)
        {
            return status;
        }
         
        ngx_str_t type =ngx_string(CONTENT_TYPE);
        r->headers_out.status = NGX_HTTP_OK;
        r->headers_out.content_type = type;
        //r->headers_out.content_length_n = reply_len;
        r->headers_out.content_length_n = response.len;

        ngx_buf_t  *b = ngx_create_temp_buf(r->pool, response.len);
        if(b == NULL)
        {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    
        ngx_memcpy(b->pos, response.data, response.len);
        b->last = b->pos+response.len;
        b->last_buf = 1;
    
        out.buf = b;
        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); 
    }
    else
    {
        return NGX_HTTP_NOT_ALLOWED;
    }   
}

static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
{
    static char uri[PB_SIZE];
    static char decode[PB_SIZE];
    char* body = NULL;
    int body_size = 0;
    char* src;
    char* dst;
    //char *reply=0;
    int status=NGX_HTTP_OK;
    //int reply_len=0;
    ngx_int_t     rc;
    ngx_chain_t   out;
    
    ngx_chain_t* bufs = r->request_body->bufs;
    ngx_buf_t* buf = NULL;
    uint8_t* data_buf = NULL;
    size_t content_length = 0;
    size_t body_length = 0;
    
    //get uri
    if (r->uri.len>=PB_SIZE)
    {
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }   
    ngx_memcpy(uri,r->uri.data,r->uri.len);
    uri[r->uri.len]=0;
    src = uri;
    dst = decode;
    ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->uri.len, 0);
    ngx_memcpy(uri,decode,dst - decode);
    uri[dst - decode] = '\0';
        
    //get body
    if (r->request_body == NULL)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "reqeust_body:null");
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    } 
    if ( r->headers_in.content_length == NULL )
    {   
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "r->headers_in.content_length == NULL");
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }
    
    content_length = atoi( (char*)(r->headers_in.content_length->value.data) );
    data_buf = ( uint8_t* )ngx_palloc( r->pool , content_length + 1 );
    size_t buf_length = 0;
    while ( bufs )
    {
        buf = bufs->buf;
        bufs = bufs->next;
        buf_length = buf->last - buf->pos ;
        if( body_length + buf_length > content_length )
        {
            memcpy( data_buf + body_length, buf->pos, content_length - body_length);
            body_length = content_length ;
            break;
        }
        memcpy( data_buf + body_length, buf->pos, buf->last - buf->pos );
        body_length += buf->last - buf->pos;
    }
    if ( body_length )
    {
        data_buf[body_length] = 0;
    }
    body = (char *)data_buf;
    body_size = body_length;
    
    //int sequence = getSequence(r);

    //reply = mypost(uri, body, body_size,sequence,&status, &reply_len);
    //ÕâÀïmypostÆäʵ¾ÍÊÇÀ©Õ¹´¦ÀípostÌá½»±íµ¥Êý¾Ýbody£¬¿ÉÒÔ°Ñ´æµ½dbÖÐÖ®ÀàµÄÆäËûÈÎÒâÒµÎñÂß¼­
    ngx_str_t response = ngx_string("Hello World!");
    if(status != NGX_HTTP_OK)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Post failed.");
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }
    
    ngx_str_t type =ngx_string(CONTENT_TYPE);
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_type = type;
    //r->headers_out.content_length_n = reply_len;
    r->headers_out.content_length_n = response.len;
    
    ngx_buf_t  *b = ngx_create_temp_buf(r->pool, response.len);
    if(b == NULL)
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return;
    }
    
    ngx_memcpy(b->pos, response.data, response.len);
    b->last = b->pos+response.len;
    b->last_buf = 1;
    
    out.buf = b;
    out.next = NULL;
    
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) 
    {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to do ngx_http_send_header.");
        ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
        return ;
    }
    
    ngx_http_finalize_request(r,ngx_http_output_filter(r, &out));   
    
    return;
}

你可能感兴趣的:(linux,Nginx探索,云计算&分布式)