1.初始化
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
};
1.解析 command :
commands数组用于定义模块的配置文件参数,每一个数组元素都是ngx_command_t类型,数组的结尾用ngx_null_command表示。Nginx在解析配置文件中的一个配置项时首先会遍历所有的模块,对于每一个模块而言,即通过遍历commands数组进行,另外,在数组中检查到ngx_null_command时,会停止使用当前模块解析该配置项。每一个ngx_command_t结构体定义了自己感兴趣的一个配置项:
其余参考定义一个自己的http模板_编程界的谢菲尔德的博客-CSDN博客
2.回调实现
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)
{
// 必须是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;
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;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos + response.len;//这是最后一块缓冲区
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next = NULL;
/*最后一步为发送包体,发送结束后 HTTP框架会调用ngx_http_finalize_request方法结束请求*/
return ngx_http_output_filter(r, &out);
}
1.ngx_http_mytest
.ngx_http_mytest是ngx_command_t结构体中的set成员(完整定义为char*(*set(ngx_conf_t*cf,ngx_command_t*cmd,void*conf);)当在某个配置块中出现mytest配置项时
nginx将会调用ngx_http_mytest方法
2.ngx_http_core_loc_conf_t:首先找到mytest配置项所属的配置块,clcf看上去像是location块内的数据结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说,在每个http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体
3. HTTP框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果请求的主机域名、URI与mytest配置项所在的配置块相匹配,就将调用我们实现的ngx_http_mytest_handler方法处理这个请求
2.static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
1.Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型。在互联网中有成百上千中不同的数据类型,HTTP在传输数据对象时会为他们打上称为MIME的数据格式标签,用于区分数据类型
2.内存问题:
分配完内存后,可以向这段内存写入数据。当写完数据后,要让b->last指针指向数据的 末尾,如果b->last与b->pos相等,那么HTTP框架是不会发送一个字节的包体的。
note:
注意 在向用户发送响应包体时,必须牢记Nginx是全异步的服务器,也就是说,不 可以在进程的栈里分配内存并将其作为包体发送。当一直ngx_http_output_filter方法返回时, 可能由于TCP连接上的缓冲区还不可写,所以导致ngx_buf_t缓冲区指向的内存还没有发送, 可这时方法返回已把控制权交给Nginx了,又会导致栈里的内存被释放,最后就会造成内存 越界错误。因此,在发送响应包体时,尽量将ngx_buf_t中的pos指针指向从内存池里分配的 内存。