5.3.6 在ngx_http_mytest_handler方法中启动upstream

在开始介入处理客户端请求的ngx_http_mytest_handler方法中启动upstream机制,而何时请求会结束,则视Nginx与上游的google服务器间的通信而定。通常,在启动upstream时,我们将决定以何种方式处理上游响应的包体,前文说过,我们会原封不动地转发google的响应包体到客户端,这一行为是由ngx_http_request_t结构体中的subrequest_in_memory标志位决定的,默认情况下,subrequest_in_memory为0,即表示将转发上游的包体到下游。在5.3.1节中介绍过,当ngx_http_upstream_conf_t结构体中的buffering标志位为0时,意味着以固定大小的缓冲区来转发包体。


static ngx_int_t

ngx_http_mytest_handler(ngx_http_request_t*r)

{

//首先建立HTTP上下文结构体ngx_http_mytest_ctx_t

ngx_http_mytest_ctx_t*myctx=ngx_http_get_module_ctx(r,ngx_http_mytest_module);

if(myctx==NULL)

{

myctx=ngx_palloc(r->pool,sizeof(ngx_http_mytest_ctx_t));

if(myctx==NULL)

{

return NGX_ERROR;

}

//将新建的上下文与请求关联起来

ngx_http_set_ctx(r,myctx,ngx_http_mytest_module);

}

/对每1个要使用upstream的请求,必须调用且只能调用1次ngx_http_upstream_create方法,它会初始化r->upstream成员/

if(ngx_http_upstream_create(r)!=NGX_OK){

ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"ngx_http_upstream_create()failed");

return NGX_ERROR;

}

//得到配置结构体ngx_http_mytest_conf_t

ngx_http_mytest_conf_tmycf=(ngx_http_mytest_conf_t)ngx_http_get_module_loc_conf(r,ngx_http_mytest_module);

ngx_http_upstream_t*u=r->upstream;

//这里用配置文件中的结构体来赋给r->upstream->conf成员

u->conf=&mycf->upstream;

//决定转发包体时使用的缓冲区

u->buffering=mycf->upstream.buffering;

//以下代码开始初始化resolved结构体,用来保存上游服务器的地址

u->resolved=(ngx_http_upstream_resolved_t*)ngx_pcalloc(r->pool,sizeof(ngx_http_upstream_resolved_t));

if(u->resolved==NULL){

ngx_log_error(NGX_LOG_ERR,r->connection->log,0,

"ngx_pcalloc resolved error.%s.",strerror(errno));

return NGX_ERROR;

}

//这里的上游服务器就是www.google.com

static struct sockaddr_in backendSockAddr;

struct hostentpHost=gethostbyname((char)"www.google.com");

if(pHost==NULL)

{

ngx_log_error(NGX_LOG_ERR,r->connection->log,0,

"gethostbyname fail.%s",strerror(errno));

return NGX_ERROR;

}

//访问上游服务器的80端口

backendSockAddr.sin_family=AF_INET;

backendSockAddr.sin_port=htons((in_port_t)80);

charpDmsIP=inet_ntoa((struct in_addr*)(pHost->h_addr_list[0]));

backendSockAddr.sin_addr.s_addr=inet_addr(pDmsIP);

myctx->backendServer.data=(u_char*)pDmsIP;

myctx->backendServer.len=strlen(pDmsIP);

//将地址设置到resolved成员中

u->resolved->sockaddr=(struct sockaddr*)&backendSockAddr;

u->resolved->socklen=sizeof(struct sockaddr_in);

u->resolved->naddrs=1;

//设置3个必须实现的回调方法,也就是5.3.3节~5.3.5节中实现的3个方法

u->create_request=mytest_upstream_create_request;

u->process_header=mytest_process_status_line;

u->finalize_request=mytest_upstream_finalize_request;

//这里必须将count成员加1,参见5.1.5节

r->main->count++;

//启动upstream

ngx_http_upstream_init(r);

//必须返回NGX_DONE

return NGX_DONE;

}


到此为止,高性能地访问第三方服务的upstream例子就介绍完了。在本例中,可以完全异步地访问第三方服务,并发访问数也只会受制于物理内存的大小,完全可以轻松达到几十万的并发TCP连接。