1.ngx_http_mytest_module.c
/*
* Copyright (C) Maxim Dounin
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
ngx_str_t response_json; //注意这里尽量定义成nginx支持的类型,否则赋值时可能出现问题
} ngx_http_mytest_ctx_t;
static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t mytest_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc);
static void mytest_post_handler(ngx_http_request_t *r);
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_LOC_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 mytest_subrequest_post_handler(ngx_http_request_t *r, void *data, ngx_int_t rc)
{
ngx_http_request_t *pr = r->parent; //当前请求的r是子请求,parent指向父请求
ngx_http_mytest_ctx_t* myctx = ngx_http_get_module_ctx(pr,ngx_http_mytest_module); //获取父请求的上下文
pr->headers_out.status = r->headers_out.status;
if(r->headers_out.status == NGX_HTTP_OK) //返回ok意味着子请求访问服务器成功,开始解析返回的HTTP包体
{
ngx_buf_t* pRecvBuf = &r->upstream->buffer;
myctx->response_json.data = pRecvBuf->pos;
myctx->response_json.len = pRecvBuf->last - pRecvBuf->pos; //接收返回数据
}
pr->write_event_handler = mytest_post_handler; //注册父请求回调函数
return NGX_OK;
}
//父请求处理方法
static void mytest_post_handler(ngx_http_request_t *r)
{
if(r->headers_out.status != NGX_HTTP_OK) //如果没有返回200,则直接把错误码发回用户
{
ngx_http_finalize_request(r, r->headers_out.status);
return;
}
ngx_http_mytest_ctx_t* myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module); //取上下文
ngx_str_t output_format = ngx_string("大家好我是%V"); //定义发送给用户的HTTP包体内容
int bodylen = output_format.len + myctx->response_json.len - 2; //计算包体长度
//在内存池上分配内存,保存要发送的包体
ngx_buf_t* b = ngx_create_temp_buf(r->pool, bodylen);
ngx_snprintf(b->pos, bodylen, (char*)output_format.data, &myctx->response_json);
b->last = b->pos + bodylen;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next = NULL;
static ngx_str_t type = ngx_string("text/plain"); //设置返回字体
r->headers_out.content_type = type;
r->headers_out.status = NGX_HTTP_OK;
r->connection->buffered |= NGX_HTTP_WRITE_BUFFERED;
ngx_int_t ret = ngx_http_send_header(r);
ret = ngx_http_output_filter(r, &out);
ngx_http_finalize_request(r, ret); //注意这里必须手动调用函数结束请求,因为这时HTTP框架不会再帮助调用它
}
//启动subrequest
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
//创建HTTP上下文
ngx_http_mytest_ctx_t* myctx = ngx_http_get_module_ctx(r, ngx_http_mytest_module);
if(myctx == NULL)
{
myctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mytest_ctx_t));
if(myctx == NULL)
{
return NGX_ERROR;
}
//将上下文设置到原始请求r中
ngx_http_set_ctx(r,myctx,ngx_http_mytest_module);
}
//创建子请求结构体
ngx_http_post_subrequest_t *psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if(psr == NULL)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
psr->handler = mytest_subrequest_post_handler; //设置子请求的回调函数为mytest_subrequest_post_handler
psr->data = myctx; //将子请求中的参数data设置为myctx,这样在回调mytest_subrequest_post_handler函数时传入的data参数就是myctx
/*获取nginx的conf文件中location为list的子请求要转到的ip*/
ngx_str_t sub_prefix = ngx_string("/list=");
ngx_str_t sub_location;
sub_location.len = sub_prefix.len + r->args.len;
sub_location.data = ngx_palloc(r->pool, sub_location.len);
ngx_snprintf(sub_location.data, sub_location.len, "%V%V", &sub_prefix, &r->args);
//sr就是子请求
ngx_http_request_t *sr;
ngx_int_t rc = ngx_http_subrequest(r, &sub_location, NULL, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY); //调用函数传入设置的参数,注册子请求,等待HTTP框架处理
if(rc != NGX_OK)
{
return NGX_ERROR;
}
return NGX_DONE; //这里必须返回NGX_DONE
}
2.nginx.conf
.............
server{
listen 2222;
location /mytest {
mytest;
}
location /list {
proxy_pass http://127.0.0.1:1111/response;
proxy_set_header Accept-Encoding ""; //不压缩返回
}
}
3.测试方法:
1)将此nginx服务复制,并修改配置文件如下:
server{
listen 1111;
location /response {
return 200 'caixukun';
}
}
2)将两个服务都启动
3)使用postman访问http://ip:2222/mytest即可得到返回 大家好我是caixukun