nginx phase handler的原理和选择
nginx phase handler的原理和选择
PHASE HANDLER的种类
nginx在接收并解析完请求行。请求头之后。就会依次调用各个phase handler。 phase handler是完毕nginx主要功能的阶段。
Nginx有例如以下11种phase,phase会依次运行。同一个phase。可能会挂载多个handler。
当中斜体加粗的phase,不同意挂载用户自己定义的handler
PHASE | 备注 |
---|---|
NGX_HTTP_POST_READ_PHASE | 读取请求内容阶段 |
NGX_HTTP_SERVER_REWRITE_PHASE | Server请求地址重写阶段 |
NGX_HTTP_FIND_CONFIG_PHASE | 配置查找阶段 |
NGX_HTTP_REWRITE_PHASE | Location请求地址重写阶段 |
NGX_HTTP_POST_REWRITE_PHASE | 请求地址重写提交阶段 |
NGX_HTTP_PREACCESS_PHASE | 訪问权限检查准备阶段 |
NGX_HTTP_ACCESS_PHASE | 訪问权限检查阶段 |
NGX_HTTP_POST_ACCESS_PHASE | 訪问权限检查提交阶段 |
NGX_HTTP_TRY_FILES_PHASE | 配置项try_files处理阶段 |
NGX_HTTP_CONTENT_PHASE | 内容产生阶段 |
NGX_HTTP_LOG_PHASE | 日志模块处理阶段 |
怎样注冊phase handler
普通情况下。我们自己定义的模块,大多数是挂载在NGX_HTTP_CONTENT_PHASE阶段的。
挂载的动作通常是在模块上下文调用的postconfiguration函数中。
挂载的代码示比例如以下:
static ngx_int_t
ngx_http_hello_init(ngx_conf_t *cf) // postconfiguration hook点
{
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_hello_handler; return NGX_OK;
}
cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers 是content phase阶段的handler数组,类似的:
cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers
cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers
cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers
。
。
。
每一个可挂载的phase。都有一个phase handler数组, 你能够选择挂载在不同的phase数组里
Nginx在解析http的配置时,会将多个phase handler数组,合成为一个数组
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) // http指令的hook函数
{
。。。
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
} module = ngx_modules[m]->ctx; if (module->postconfiguration) {
if (module->postconfiguration(cf) != NGX_OK) {// 运行各模块的postconfigure hook, phase handler就在此时挂载
return NGX_CONF_ERROR;
}
}
}
。。 。
if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {// 将多个phase handler数组。合成为一个数组
return NGX_CONF_ERROR;
}
。。。
}
ngx_http_init_phase_handlers(cf, cmcf) 函数将(除log phase以外的)几个phase handler数组。合成为一个ngx_http_phase_handler_t类型的数组
struct ngx_http_phase_handler_s {
ngx_http_phase_handler_pt checker; // 检查handler返回结果。决定下一个运行的handler
ngx_http_handler_pt handler; // handler 钩子
ngx_uint_t next; // 指向下一个phase的第一个handler
};
下面是不同的phase。相应不同的checker函数
PHASE | checker |
---|---|
NGX_HTTP_POST_READ_PHASE | ngx_http_core_generic_phase |
NGX_HTTP_SERVER_REWRITE_PHASE | ngx_http_core_rewrite_phase |
NGX_HTTP_FIND_CONFIG_PHASE | ngx_http_core_find_config_phase |
NGX_HTTP_REWRITE_PHASE | ngx_http_core_rewrite_phase |
NGX_HTTP_POST_REWRITE_PHASE | ngx_http_core_post_rewrite_phase |
NGX_HTTP_PREACCESS_PHASE | ngx_http_core_generic_phase |
NGX_HTTP_ACCESS_PHASE | ngx_http_core_access_phase |
NGX_HTTP_POST_ACCESS_PHASE | ngx_http_core_post_access_phase |
NGX_HTTP_TRY_FILES_PHASE | ngx_http_core_try_files_phase |
NGX_HTTP_CONTENT_PHASE | ngx_http_core_content_phase |
NGX_HTTP_LOG_PHASE | ngx_http_core_generic_phase |
Phase handler怎样运行
nginx在接收并解析完请求行。请求头之后。就会依次调用各个phase handler.
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
能够看到,事实上依次运行的就是我们在初始化阶段,生成的ngx_http_phase_handler_t 数组
我们通过debug。来看一下ngx_http_phase_handler_t数组的实际内容
执行中时ph数组的内容 | |||
---|---|---|---|
数组下标 | checker | handler | next |
0 | ngx_http_core_rewrite_phase | ngx_http_rewrite_handler | 1 |
1 | ngx_http_core_find_config_phase | 0 | 0 |
2 | ngx_http_core_rewrite_phase | ngx_http_rewrite_handler | 3 |
3 | ngx_http_core_post_rewrite_phase | 0 | 1 |
4 | ngx_http_core_generic_phase | ngx_http_l7waf_handler | 7 |
5 | ngx_http_core_generic_phase | ngx_http_limit_req_handler | 7 |
6 | ngx_http_core_generic_phase | ngx_http_limit_conn_handler | 7 |
7 | ngx_http_core_access_phase | ngx_http_access_handler | 10 |
8 | ngx_http_core_access_phase | ngx_http_auth_basic_handler | 10 |
9 | ngx_http_core_post_access_phase | 0 | 10 |
10 | ngx_http_core_try_files_phase | 0 | 0 |
11 | ngx_http_core_content_phase | ngx_http_index_handler | 14 |
12 | ngx_http_core_content_phase | ngx_http_autoindex_handler | 14 |
13 | ngx_http_core_content_phase | ngx_http_static_handler | 14 |
14 | 0 | 0 | 0 |
我们来看一个详细的checker函数
ngx_int_t
ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc; /*
* generic phase checker,
* used by the post read and pre-access phases
*/ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"generic phase: %ui", r->phase_handler); rc = ph->handler(r); // 运行挂载的handler if (rc == NGX_OK) { // 返回值是NGX_OK。说明这个phase运行完了,跳到下一个phase的第一个handler去
r->phase_handler = ph->next;
return NGX_AGAIN;
} if (rc == NGX_DECLINED) { // 返回值NGX_DECLINED,继续运行这个phase的下一个handler
r->phase_handler++;
return NGX_AGAIN;
} if (rc == NGX_AGAIN || rc == NGX_DONE) { //说明请求处理完了。以下全部的phase handler都不须要再运行了
return NGX_OK;
} /* rc == NGX_ERROR || rc == NGX_HTTP_... */ ngx_http_finalize_request(r, rc); // 返回错误,结束请求,返回对应的错误页 return NGX_OK;
}
怎样选择哪个phase
读取请求内容阶段
这个阶段没有默认的handler。主要用来读取请求体。并对请求体做对应的处理
Server请求地址重写阶段
这个阶段主要是处理全局的(server block)的rewrite规则
配置查找阶段
这个阶段主要是通过uri来查找相应的location。
然后将uri和location的数据关联起来。
这个阶段主要处理逻辑在checker函数中。不能挂载自己定义的handler
Location请求地址重写阶段
这个主要处理location block的rewrite。
请求地址重写提交阶段
post rewrite,这个主要是进行一些校验以及收尾工作,以便于交给后面的模块。这个phase不能挂载自己定义handler
訪问权限检查准备阶段
比方流控这样的类型的access就放在这个phase,也就是说它主要是进行一些比較粗粒度的access。
訪问权限检查阶段
这个比方存取控制,权限验证就放在这个phase,一般来说处理动作是交给以下的模块做的.这个主要是做一些细粒度的access。
訪问权限检查提交阶段
一般来说当上面的access模块得到access_code之后就会由这个模块依据access_code来进行操作 这个phase不能挂载自己定义handler
配置项try_files处理阶段
try_file模块,也就是相应配置文件里的try_files指令。
这个phase不能挂载自己定义handler
按顺序检查文件是否存在,返回第一个找到的文件。结尾的斜线表示为目录 -$uri/。假设全部的文件都找不到。会进行一个内部重定向到最后一个參数。
内容产生阶段
内容处理模块,产生文件内容,假设是php。去调用phpcgi。假设是代理,就转发给对应的后端server
日志模块处理阶段
日志处理模块,是每一个请求最后一定会运行的。用于打印訪问日志。
通过如上对phase handler的分析,我们能够知道nginx划分不同的phase,是将不同功能,安排在不同的顺序运行。
选择挂载在哪个phase,就选择了handler运行的顺序。而且选择了不同的checker函数。
自己定义的handler有时候能够挂载在不同的phase,都能够正常执行。
自己定义的handler,假设依赖某一个phase的结果。则必须挂载在该phase后面的phase上。
自己定义的handler须要遵守nginx对不同phase的功能划分,但没必要的。
除去4个不能挂载的phase,和log phase,还有例如以下6个phase能够挂载
NGX_HTTP_POST_READ_PHASE
NGX_HTTP_SERVER_REWRITE_PHASE
NGX_HTTP_REWRITE_PHASE
NGX_HTTP_PREACCESS_PHASE
NGX_HTTP_ACCESS_PHASE
NGX_HTTP_CONTENT_PHASE
非常多功能挂载在这6个phase,都能够实现。挂载在越前面。我们的性能会越好,挂载在后面,我们的自由度会更大。
比方说,假设我们实如今NGX_HTTP_POST_READ_PHASE 阶段。我们就不能用 location if 这些后面阶段实现的指令来组合实现一些更复杂的功能。
推荐使用
NGX_HTTP_PREACCESS_PHASE
NGX_HTTP_ACCESS_PHASE
NGX_HTTP_CONTENT_PHASE
nginx phase handler的原理和选择的更多相关文章
- Nginx 反向代理工作原理简介与配置详解
Nginx反向代理工作原理简介与配置详解 by:授客 QQ:1033553122 测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...
- android handler工作原理
android handler工作原理 作用 便于在子线程中更新主UI线程中的控件 这里涉及到了UI主线程和子线程 UI主线程 它很特别.通常我们会认为UI主线程将页面绘制完成,就结束了.但是它没有. ...
- Nginx 解析PHP的原理 | CGI、FastCGI及php-fpm的关系
Nginx解析PHP的原理,CGI/FastCGI以及PHP-Fpm的关系. 一.PHP+Nginx应运而生的场景.随着互联网的发展,用户对此接受面广,数据流的增大使得Web端的运行承载压力日益增大, ...
- android高级---->Handler的原理
andriod提供了Handler来满足线程间的通信,上次在更新UI的时候也提到过Handler的使用,关于Handler的基本使用,参见博客(android基础---->子线程更新UI).今天 ...
- Nginx解析PHP的原理 | CGI、FastCGI及php-fpm的关系
Nginx解析PHP的原理,CGI/FastCGI以及PHP-Fpm的关系. 一.PHP+Nginx应运而生的场景.随着互联网的发展,用户对此接受面广,数据流的增大使得Web端的运行承载压力日益增大, ...
- Nginx基本功能及其原理,配置原理
Nginx基本功能及其原理,配置原理 一.正向代理.反向代理 二.Nginx配置文件的整体结构 三.Nginx配置SSL及HTTP跳转到HTTPS 四.nginx 配置管理 [nginx.conf 基 ...
- Nginx与PHP工作原理
Nginx的工作原理 1.Nginx的模块与工作原理 Nginx由内核和模块组成,其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location bl ...
- Nginx,LVS,HAProxy,负载均衡之选择
Nginx的优点:性能好,可以负载超过1万的并发.功能多,除了负载均衡,还能作Web服务器,而且可以通过Geo模块来实现流量分配.社区活跃,第三方补丁和模块很多支持gzip proxy缺点:不支持se ...
- Nginx与PHP-FPM运行原理详解
目录 1. 代理与反向代理 1. 正向代理:访问google.com 2. 反向代理:通过反向代理实现负载均衡 2. 初识Nginx与PHP-FPM 1. Nginx是什么 2. CGI与FastCG ...
随机推荐
- PostgreSQL 行排序详解
在查询生成输出表之后,也就是在处理完选择列表之后,你还可以对输出表进行排序. 如果没有排序,那么行将以不可预测的顺序返回(实际顺序将取决于扫描和连接规划类型和在磁盘上的顺序, 但是肯定不能依赖这些东西 ...
- python实现算法: 多边形游戏 数塔问题 0-1背包问题 快速排序
去年的算法课挂了,本学期要重考,最近要在这方面下点功夫啦! 1.多边形游戏-动态规划 问题描述: 多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形.每个顶点被赋予一个整数值, 每条边被 ...
- Hadoop架构的初略总结(2)
Hadoop架构的初略总结(2) 回顾一下前文,我们总结了以下几个方面.我们为什么需要Hadoop:Hadoop2.0生态系统的构成:Hadoop1.0中HDFS和MapReduce的结构模型. 我们 ...
- Spring Cloud 目录
Spring Cloud Eureka Spring Cloud Config Spring Cloud Feign Spring Cloud Hystrix Spring Cloud Ribbon ...
- 计算两个日期之间的天数差C++/java
1--Java 分析:调用java中Calendar类 int days(Date date1,Date date2){ Calendar cal = new Calendar.getInstance ...
- 【转】Netty系列之Netty编解码框架分析
http://www.infoq.com/cn/articles/netty-codec-framework-analyse/ 1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称 ...
- call、apply与bind在理解
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法. fun.call(thisArg[, arg1[, arg2[, ...]]]) apply() 方法 ...
- arcgis engine10.1和arcObjects的一些问题
1.arcengine10.1只支持vs2010 2.10.1以后没有engine runtimes,改成engine了,以前的engine可以理解为Arcobject,就是我们可以只装AO
- ios - 工具类
这几天看项目,把俺旁边小哥哥的一个工具类相中了,希望对大家有所帮助哦~~~~~~~~~ // // PLZ_Tool.h // // Created by penglaizhi on 2017/7/3 ...
- iOS - 毛玻璃效果封装
#import <UIKit/UIKit.h> #import <Accelerate/Accelerate.h> @interface UIImage (TY_ImageEd ...