译文:Nginx多阶段处理HTTP请求

原文:http://www.nginxguts.com/2011/01/phases/

Nginx processes HTTPrequests in multiple phases. In each of the phases there might be 0 or morehandlers called. In the Nginx source code phases have specific constantsassociated with them. Here is a list of all phases:

Nginx以多个阶段(phases)处理HTTP请求。对于每个阶段可能有0个多个handler被调用。在Nginx源码中都有常量名称标识各个阶段,下面是所有阶段的列表:

1.NGX_HTTP_SERVER_REWRITE_PHASE— the phase of request URI transformation on virtual server level;

2.NGX_HTTP_FIND_CONFIG_PHASE— the phase of configuration location lookup;

3.NGX_HTTP_REWRITE_PHASE —the phase of request URI transformation on location level;

4.NGX_HTTP_POST_REWRITE_PHASE— request URI transformation post-processing phase;

5.NGX_HTTP_PREACCESS_PHASE —access restrictions check preprocessing phase;

6.NGX_HTTP_ACCESS_PHASE —access restrictions check phase;

7.NGX_HTTP_POST_ACCESS_PHASE— access restrictions check post-processing phase;

8.NGX_HTTP_TRY_FILES_PHASE —try_files directive processing phase;

9.NGX_HTTP_CONTENT_PHASE —content generation phase;

10.NGX_HTTP_LOG_PHASE —logging phase.

On every phase you canregister any number of your handlers.Exceptions are following phases:

在每个阶段你都可以注册多个自定义的hanlders。除了下面几个阶段。

••NGX_HTTP_FIND_CONFIG_PHASE.On this phase no handlers are called, instead a search for configurationlocation is performed and “Location” request header is filled.

•NGX_HTTP_POST_ACCESS_PHASE.On this phase no handlers are called,

only the result of accesschecks is interpreted and applied. The phase is required to implement directivesatisfy all/any.

•NGX_HTTP_POST_REWRITE_PHASE.On this phase no handlers are called,

instead request URItransformation post-processing is performed;

•NGX_HTTP_TRY_FILES_PHASE.On this phase no handlers are called,

instead Nginx processes thetry_files directive.

Each phase has a list ofhandlers associated with it. Once registered on a phase, handler can return oneof the following values:

每个阶段都有一个与之相关的handler的列表。一旦把handler注册到对应的阶段,那么handler就会返回某个下面的值:

NGX_OK:请求已经成功处理,请求将会传到下一个阶段。

NGX_DECLINED:请求需要被转发到本阶段的下一个handler

NGX_AGAIN,NGX_DONE:请求已经被正确处理,同时请求被挂起,直到某个事件(子请求结束、socket可写或超时等)到来,handler才会再次被调用。

•NGX_OK — the requesthas been successfully processed, request must be routed to the next phase;

•NGX_DECLINED —request must be routed to the next handler;

•NGX_AGAIN, NGX_DONE —the request has been successfully processed, the request must be suspendeduntil some event (e.g., subrequest finishes, socket becomes writeable ortimeout occurs) and handler must be called again;

•NGX_ERROR, NGX_HTTP_…— an error has occurred while processing the request.

In order to register ahandler you need to find the configuration of ngx_http_core_module and add thehandler to one of elements of phases vector. Example:

为了在某个阶段注册自定义的handler,需要找到ngx_http_core_module,并添加handler到指定的phases 向量中。

static ngx_int_t

ngx_http_sample_module_init(ngx_conf_t*cf)

{

ngx_http_handler_pt *h;

ngx_http_core_main_conf_t *cmcf;

cmcf=ngx_http_conf_get_module_main_conf(cf,ngx_http_core_module);

h=ngx_array_push(&cmcf>phases[NGX_HTTP_CONTENT_PHASE].handlers);

if (h == NULL) {

return NGX_ERROR;

}

*h = ngx_http_sample_module_handler;

return NGX_OK;

}

The vector phases has oneentry for each phase. Each entry contains a field handlers which is a vector ofhandlers that are registered on this phase.

Handlers are called inreverse order. Therefore the last handler registered at configuration time willbe called first at runtime.

As you can see, the order ofactions in request processing has nothing to do with the order of directives inconfiguration file. Phase handlers are called regardless of what configurationthe user has specified. Hence a phase handler must be able to determine when itis applicable and return NGX_DECLINED when it is not and do it as fast as possibleto avoid performance penalties.

从上面可以看出,请求处理的顺序和配置文件中的配置指令的先后顺序无关,无论配置文件中指令的顺序如何,各个阶段的处理函数都会按照预先的顺序执行。因此一个处理函数需要知道自己什么时候会被调用,何时需要返回NGX_DECLINED,而且保证减少性能损耗。

The phaseNGX_HTTP_ACCESS_PHASE calls handlers that restrict access to resources. In thisphase the order in which handlers are called is determined by directivesatisfy. The values, that handlers return, have additional meaning:

NGX_OK — handler allows toaccess the resource specified by request URI;

NGX_HTTP_FORBIDDEN,NGX_HTTP_UNAUTHORIZED — handler does not allow to request the resourcespecified by request URI.

In case of satisfy all allhandlers must return NGX_OK in order to proceed with the next phase.

In case of satisfy any atleast one handler must return NGX_OK in order to proceed with the next phase.

Nginx uses the phaseNGX_HTTP_CONTENT_PHASE to generate a response. Whenever a locationconfiguration of ngx_http_core_module has handler field initialized, allrequests on content phase are routed to this handler. The handler that isspecified by handler field is hence called content handler. When contenthandler is not set, request is routed to handlers of content phase in mainconfiguration.

Nginx使用阶段NGX_HTTP_CONTENT_PHASE产生响应。无论何时,ngx_http_core_module的location配置中都有handler字段的初始化,所有请求在content phase处理时都会转发到这个handler。这个handler是由handler字段指定。因此这个handler字段又称为content handler。当content handler不指定时,请求就会转发到主配置中的contentphase的各个handler中。

这儿我经过验证,果真如此,即:如果不指定ngx_http_core_loc_conf_t->handler,那么请求转发到默认的content phase中的handler(如ngx_http_index_handler,ngx_http_static_handler);但是如果指定了ngx_http_core_loc_conf_t->handler,那么请求就会转发到该指定的handler中处理,生成内容。hello_world模块是后者,http://localhost输出welcome to Nginx!是前者。可以在函数内部输入printf,看输出,就可以更加明确这一点。

How to overridecontent handler? Here is an example:

如何指定content handler呢?如下所示:

static char *

ngx_http_sample_module_command(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_sample_handler;

returnNGX_CONF_OK;

}

Thecontent handler has following specific properties:

Contenthandler 有下面特殊的属性:

1)不能再被调用。就说说,当返回NGX_AGAIN与NGX_DONE时,content handler不会再被调用。取而代之的是handler必须改变请求的读或写handler

2)每个location都有他自己的content handler。

3)如果content handler 返回NGX_DECLINED,Nginx转发请求道content phase handlers。

•It is not resumable. That is, it’s not going to be called again ifit returns NGX_AGAIN or NGX_DONE. Instead the handler must change read and/orwrite handlers of the request;

•Each location can have it’s own dedicated content handler;

•If content handler returns NGX_DECLINED, Nginx routes request tocontent phase handlers.

Howdo you find out which phase to put your handler on?

Although this blog is not to criticizeNginx, here seems to be a bit of a problem. According to my feelings and toIgor Sysoev comments, phases are legacy from Apache. They are not as flexiblefor a module developer as you would expect. Clearly this point could beimproved (and it will be), but for the moment here are suggestions, that youcan use in order to figure out what phase you need to put your handler on:

•Your handler needs to be manageable by satisfy directive (e.g.access restriction checks) — put it on access phase;

•Your handler does resource limitations — put it on pre-access phase;

•Your handler changes URI or manipulates variables than need to beaccessible in set directive or rewrites — put it on rewrite phase;

•Your handler generates content — put it on content phase, take careof the handler registration order;

•Your handler does logging — put it on logging phase;

When you should use content handlers?

What is the difference between contentphase handler and content handler?

•the content phase handler is promiscuous: it is called for everyrequest that reaches the content phase and this particular handler. The contenthandler is called only for those requests that reach a location with configuredcontent handler;

•more than one content phase handler can be called per location. Onlyone content handler can be called per location.

A combination of these two types ofhandlers are employed by nginx mogilefs module for doing PUT requests:

Main location is handled by a contentphase handler. This handler has 3 stages that correspond to create_opencommand, storing the resource on storage node and create_close command. On eachstage content phase handler does a subrequest. When subrequest finishes, itwakes up the main content phase handler. In case of create_open and create_close commands subrequest is routed toa hidden location that has a content handler set up in it. This handlerimplements communication with MogileFS tracker using upstream module.

本文分享自微信公众号 - nginx遇上redis(GGame_over_the_world)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏arebirth重生者的IT之路

SpringMVC运行原理

按照上边的执行流程图,我们可以看出一个SpringMVC整体的一个执行轮廓,下面我们具体来分析下

13440
来自专栏Android技术分享

Android性能优化之APK 极限压缩(资源越多,效果越显著)

随着项目的不断迭代,代码量跟资源文件不断增多。那么就会出现打包后的 APK 文件越来越大,如果突然有一天你们老板或领导叫你优化 APK 大小,你还不知道怎么优化...

17530
来自专栏Python绿色通道

薅羊毛 | Python 带你抢视频红包,不放过一个红包!

如今短视频横行的时代,以某短视频为首的,背后依靠着强大的资金后盾,疯狂地对平台用户进行红包轰炸。

12620
来自专栏测试开发社区

用Python拨打电话

跟selenium操作浏览器原理类似,这是用appium操作移动设备的一个自动化功能,自娱自乐,主要是通过小案例引出相关技术

16430
来自专栏美团技术团队

Litho在动态化方案MTFlexbox中的实践

MTFlexbox是美团内部应用的非常成熟的一种跨平台动态化解决方案,它遵循了CSS3中提出的Flexbox规范来抹平多平台的差异。MTFlexbox适用于重展...

12420
来自专栏安全漏洞环境学习

ES文件浏览器(CVE-2019-6447)漏洞复现

适用于Android的ES文件浏览器文件管理器应用程序是一款基于Android系统的多功能手机文件,程序和进程管理器,它支持在手机,电脑,远程和蓝牙间浏览管理文...

15260
来自专栏每天学点Android知识

Flutter状态管理(2)——单Stream和广播Stream

在Flutter状态管理(1)——InheritedWidget中介绍了状态管理以及如何使用InheritedWidget来实现全局状态的管理。这篇博客将介绍如...

14230
来自专栏程序员成长指北

微信H5页面兼容性解决方案

最近给公司微信公众号,写了微信h5业务页面,总结分享一下前端开发过程中的几个兼容性坑,项目直接拿的公司页面,所以下文涉及图片都模糊处理了。

30340
来自专栏安全漏洞环境学习

Android4 漏洞环境简单挑战

今天给各位分享的是一个Android虚拟机环境的简单渗透。按照我们一般的渗透流程大概分为:

13510
来自专栏.Net Core技术分享

手撸一套纯粹的CQRS实现

关于CQRS,在实现上有很多差异,这是因为CQRS本身很简单,但是它犹如潘多拉魔盒的钥匙,有了它,读写分离、事件溯源、消息传递、最终一致性等都被引入了框架,从而...

4710

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励