Nginx module开发利器:subrequest

nginx是个高性能web server,很多时候我们会把它当成reverse proxy或者web server container使用,但有时我们也会开发它的第三方module,因为module才能完全使用nginx的全事件驱动、无阻塞调用机制,充分使用系统资源,达到SERVER最大处理吞吐量。

在开发nginx module时,我们最有可能遇到的一件事就是,在处理一个请求时,我们需要访问其他多个backend server网络资源,拉取到结果后分析整理成一个response,再发给用户。这个过程是无法使用nginx upstream机制的,因为upstream被设计为用来支持nginx reverse proxy功能,所以呢,upstream默认是把其他server的http response body全部返回给client。这与我们的要求不符,这个时候,我们可以考虑subrequest了,nginx http模块提供的这个功能能够帮我们搞定它。

先看看subrequest调用函数长什么样:

[cpp]

ngx_int_t   ngx_http_subrequest(ngx_http_request_t *r,       ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr,       ngx_http_post_subrequest_t *ps, ngx_uint_t flags)  

挨个分析下参数吧。r是我们的module handler中,nginx调用时传给我们的请求,这时我们直接传给subrequest即可。uri和args是我们需要访问backend server的URL,而psr是subrequest函数执行完后返回给我们的新请求,即将要访问backend server的请求指针。ps指明了回调函数,就是说,如果这个请求执行完毕,接收到了backend server的响应后,就会回调这个函数。flags会指定这个子请求的一些特征。

看看ngx_http_post_subrequest的结构:

[cpp]

typedef struct {       ngx_http_post_subrequest_pt       handler;       void                             *data;   } ngx_http_post_subrequest_t;  

这里的handler你可以指向一个函数,这个函数会在这个子请求结束以后被nginx调用,这时传给函数的request是子请求,不是原始的父请求哈。

而flag我们一般只会感兴趣下面这个NGX_HTTP_SUBREQUEST_IN_MEMORY,flag设为这个宏时,表示发起的子请求,访问的网络资源返回的响应将全部放在内存中,我们可以从upstream->buffer里取到响应内容。所以这里如果用了这个flag,一定要确保返回内容不可以很大,例如不能去下载一个大文件。

所以,当我们写nginx的module时,需要去拉取某个网络资源,就可以这么写:

[cpp]

  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 = ngx_http_my_post_subrequest;     psr->data = ctx;   ngx_flag_t flag = NGX_HTTP_SUBREQUEST_IN_MEMORY    ngx_str_t sub_location = ngx_string("/testlocation");   ngx_str_t sub_args = ngx_string("para=1");;     rc = ngx_http_subrequest(r, &sub_location, &url_args, &sr, psr, sr_flag);  

这样,在这个subrequest执行完后,将会调用ngx_http_my_post_subrequest方法,再次注意,此时传给你的ngx_http_request_t上下文是子请求的,不是原始的父请求,所以,如果你需要在父请求的上下文中处理这个请求,可以在ngx_http_my_post_subrequest中找到父请求的handler,设置为一个处理函数即可。 比如:

[cpp]

ngx_http_request_t          *pr = r->parent;   pr->write_event_handler = ngx_http_parent_handler;  

这样,这个ngx_http_my_post_subrequest执行完毕后,nginx开始换醒父请求,这时ngx_http_parent_handler将会被调用。


内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pxypw.html