nginx 編寫簡單HTTP模組以及nginx http handler的hello world示例編寫

後開啟撒打發了發表於2018-01-19

編寫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 <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

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

相關文章