请求处理与钩子函数
Nginx 请求处理基于多阶段钩子机制,模块在特定阶段挂载回调函数参与请求处理链。
HTTP 请求处理阶段
11 个标准阶段
| 阶段 | 常量 | 说明 |
|---|---|---|
| 1 | NGX_HTTP_POST_READ_PHASE | 读取请求体后 |
| 2 | NGX_HTTP_SERVER_REWRITE_PHASE | server 级重写 |
| 3 | NGX_HTTP_FIND_CONFIG_PHASE | 匹配 location |
| 4 | NGX_HTTP_REWRITE_PHASE | location 级重写 |
| 5 | NGX_HTTP_POST_REWRITE_PHASE | 重写后处理 |
| 6 | NGX_HTTP_PREACCESS_PHASE | 访问控制前 |
| 7 | NGX_HTTP_ACCESS_PHASE | 访问权限检查 |
| 8 | NGX_HTTP_POST_ACCESS_PHASE | 访问控制后 |
| 9 | NGX_HTTP_PRECONTENT_PHASE | 内容处理前 |
| 10 | NGX_HTTP_CONTENT_PHASE | 生成响应内容 |
| 11 | NGX_HTTP_LOG_PHASE | 日志记录 |
阶段处理流程
C
客户端请求
→ NGX_HTTP_POST_READ_PHASE
→ NGX_HTTP_SERVER_REWRITE_PHASE
→ NGX_HTTP_FIND_CONFIG_PHASE (匹配 location)
→ NGX_HTTP_REWRITE_PHASE
→ NGX_HTTP_PREACCESS_PHASE
→ NGX_HTTP_ACCESS_PHASE (访问控制)
→ NGX_HTTP_PRECONTENT_PHASE
→ NGX_HTTP_CONTENT_PHASE (内容生成)
→ NGX_HTTP_LOG_PHASE
→ 响应返回
钩子注册机制
注册 handler
C
static ngx_int_t
ngx_http_my_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);
// 注册到 content 阶段
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_my_handler;
return NGX_OK;
}
请求处理函数
C
static ngx_int_t
ngx_http_my_handler(ngx_http_request_t *r)
{
// 检查请求方法
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
return NGX_HTTP_NOT_ALLOWED;
}
// 丢弃请求体
ngx_int_t rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
// 设置响应头
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = 12;
ngx_str_set(&r->headers_out.content_type, "text/plain");
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK) {
return rc;
}
// 发送响应体
ngx_buf_t *b;
b = ngx_create_temp_buf(r->pool, 12);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(b->pos, "Hello World!", 12);
b->last = b->pos + 12;
b->last_buf = 1;
ngx_chain_t out;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
handler 返回
NGX_OK继续处理,NGX_DECLINED跳过本模块,NGX_ERROR终止请求。
请求结构体关键字段
ngx_http_request_t 核心字段
C
struct ngx_http_request_s {
uint32_t signature;
ngx_connection_t *connection; // 底层连接
ngx_str_t request_line; // 请求行
ngx_str_t uri; // URI
ngx_str_t args; // 查询参数
ngx_str_t exten; // 文件扩展名
ngx_http_headers_in_t headers_in; // 请求头
ngx_http_headers_out_t headers_out; // 响应头
ngx_http_request_body_t *request_body; // 请求体
unsigned method; // 请求方法
unsigned http_version; // HTTP 版本
ngx_http_phase_handler phase_handler; // 当前阶段
};
过滤链机制
header_filter 过滤
C
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_int_t
ngx_http_my_header_filter(ngx_http_request_t *r)
{
// 检查是否已处理
if (r->headers_out.status != NGX_HTTP_OK) {
return ngx_http_next_header_filter(r);
}
// 修改响应头
r->headers_out.content_length_n += 10;
return ngx_http_next_header_filter(r);
}
// 初始化
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_my_header_filter;
body_filter 过滤
text
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_my_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_chain_t *cl;
for (cl = in; cl; cl = cl->next) {
// 处理每个 buffer
if (cl->buf->last_buf) {
cl->buf->last_buf = 0;
cl->buf->last_in_chain = 1;
}
}
return ngx_http_next_body_filter(r, in);
}
// 初始化
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_my_body_filter;
过滤器以链表形式执行,必须调用下一个过滤器,否则请求中断。
要点总结
- Nginx HTTP 请求经历 11 个处理阶段,模块可注册到特定阶段
- handler 注册到
cmcf->phases[].handlers数组,通过NGX_HTTP_CONTENT_PHASE等指定阶段 - 请求结构体
ngx_http_request_t封装请求全量信息 - 过滤器分 header_filter 和 body_filter 两种,形成链式调用
- 每个过滤器必须调用下一个过滤器,否则请求中断
📝 发现内容有误?点击此处直接编辑