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连接。