您的位置:首页 > 理论基础 > 计算机网络

文章13:Nginx多阶段处理HTTP请求

2012-10-13 16:00 806 查看


我自己添加的注释本文讲述了HTTP请求处理阶段的内容,非常棒的一篇文章。部分重点内容翻译如下,请大家阅读。

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


这个颜色的字体是我翻译内容

这个颜色的字体是我自己添加的注释

这个颜色的字体当然就是原文


HTTP request processing phases in Nginx

Posted on January
4, 2011 by vkholodkov



Nginx
processes HTTP requests in multiple phases. In each of the phases there might be 0 or more handlers called. In the Nginx source code phases have specific constants associated with them. Here is a list of all phases:

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

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

NGX_HTTP_FIND_CONFIG_PHASE — the phase of configuration location lookup;

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

NGX_HTTP_POST_REWRITE_PHASE — request URI transformation post-processing phase;

NGX_HTTP_PREACCESS_PHASE — access restrictions check preprocessing phase;

NGX_HTTP_ACCESS_PHASE — access restrictions check phase;

NGX_HTTP_POST_ACCESS_PHASE — access restrictions check post-processing phase;

NGX_HTTP_TRY_FILES_PHASE — try_files directive processing phase;

NGX_HTTP_CONTENT_PHASE — content generation phase;

NGX_HTTP_LOG_PHASE — logging phase.

On every phase you can register 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 configuration location is performed and “Location” request header is filled.

NGX_HTTP_POST_ACCESS_PHASE. On this phase no handlers are called,

only the result of access checks is interpreted and applied. The phase is required to implement directive satisfy all/any.

NGX_HTTP_POST_REWRITE_PHASE. On this phase no handlers are called,

instead request URI transformation post-processing is performed;

NGX_HTTP_TRY_FILES_PHASE. On this phase no handlers are called,

instead Nginx processes the try_files directive.

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

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

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

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

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



NGX_OK — the request has 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 suspended until some event (e.g., subrequest finishes, socket becomes writeable or timeout occurs) and handler must be called again;

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

In order to register a handler you need to find the configuration of ngx_http_core_module and add the handler 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 one entry for each phase. Each entry contains a field handlers which
is a vector of handlers that are registered on this phase.

Handlers are called in reverse order. Therefore the last handler registered at configuration time will be called first at runtime.



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

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

The phase NGX_HTTP_ACCESS_PHASE calls handlers that restrict access to resources. In this phase the order in which handlers are called is determined by directive satisfy.
The values, that handlers return, have additional meaning:

NGX_OK — handler allows to access the resource specified by request URI;

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

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

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

Nginx uses the phase NGX_HTTP_CONTENT_PHASE to generate a response. Whenever a location configuration of ngx_http_core_module has handler field
initialized, all requests on content phase are routed to this handler. The handler that is specified by handler field is hence called content
handler. When content handler is not set, request is routed to handlers of content phase in main configuration.

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

    return NGX_CONF_OK;
}


The content handler has following specific properties:

Content handler 有下面特殊的属性:

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 if it returns NGX_AGAIN or NGX_DONE. Instead the handler must change read and/or write handlers of the request;

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

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

How do you find out which phase to put your handler on?

Although this blog is not to criticize Nginx, here seems to be a bit of a problem. According to my feelings and to Igor Sysoev comments, phases are legacy from Apache. They are not as flexible for a module developer as you would expect. Clearly this point could
be improved (and it will be), but for the moment here are suggestions, that you can 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 be accessible in set directive or rewrites — put it on rewrite phase;

Your handler generates content — put it on content phase, take care of the handler registration order;

Your handler does logging — put it on logging phase;

When you should use content handlers?

What is the difference between content phase handler and content
handler?

the content phase handler is promiscuous: it is called for every request that reaches the content phase and this particular handler. The content
handler is called only for those requests that reach a location with configured content handler;

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

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

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

This entry was posted in Uncategorized.
Bookmark the permalink.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: