news 2026/6/3 15:10:34

ngx_http_limit_req_handler

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ngx_http_limit_req_handler

1 定义

ngx_http_limit_req_handler 函数 定义在 ./nginx-1.24.0/src/http/modules/ngx_http_limit_req_module.c
staticngx_int_tngx_http_limit_req_handler(ngx_http_request_t*r){uint32_thash;ngx_str_tkey;ngx_int_trc;ngx_uint_tn,excess;ngx_msec_tdelay;ngx_http_limit_req_ctx_t*ctx;ngx_http_limit_req_conf_t*lrcf;ngx_http_limit_req_limit_t*limit,*limits;if(r->main->limit_req_status){returnNGX_DECLINED;}lrcf=ngx_http_get_module_loc_conf(r,ngx_http_limit_req_module);limits=lrcf->limits.elts;excess=0;rc=NGX_DECLINED;#if(NGX_SUPPRESS_WARN)limit=NULL;#endiffor(n=0;n<lrcf->limits.nelts;n++){limit=&limits[n];ctx=limit->shm_zone->data;if(ngx_http_complex_value(r,&ctx->key,&key)!=NGX_OK){ngx_http_limit_req_unlock(limits,n);returnNGX_HTTP_INTERNAL_SERVER_ERROR;}if(key.len==0){continue;}if(key.len>65535){ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"the value of the \"%V\" key ""is more than 65535 bytes: \"%V\"",&ctx->key.value,&key);continue;}hash=ngx_crc32_short(key.data,key.len);ngx_shmtx_lock(&ctx->shpool->mutex);rc=ngx_http_limit_req_lookup(limit,hash,&key,&excess,(n==lrcf->limits.nelts-1));ngx_shmtx_unlock(&ctx->shpool->mutex);ngx_log_debug4(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"limit_req[%ui]: %i %ui.%03ui",n,rc,excess/1000,excess%1000);if(rc!=NGX_AGAIN){break;}}if(rc==NGX_DECLINED){returnNGX_DECLINED;}if(rc==NGX_BUSY||rc==NGX_ERROR){if(rc==NGX_BUSY){ngx_log_error(lrcf->limit_log_level,r->connection->log,0,"limiting requests%s, excess: %ui.%03ui by zone \"%V\"",lrcf->dry_run?", dry run":"",excess/1000,excess%1000,&limit->shm_zone->shm.name);}ngx_http_limit_req_unlock(limits,n);if(lrcf->dry_run){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;returnNGX_DECLINED;}r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_REJECTED;returnlrcf->status_code;}/* rc == NGX_AGAIN || rc == NGX_OK */if(rc==NGX_AGAIN){excess=0;}delay=ngx_http_limit_req_account(limits,n,&excess,&limit);if(!delay){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_PASSED;returnNGX_DECLINED;}ngx_log_error(lrcf->delay_log_level,r->connection->log,0,"delaying request%s, excess: %ui.%03ui, by zone \"%V\"",lrcf->dry_run?", dry run":"",excess/1000,excess%1000,&limit->shm_zone->shm.name);if(lrcf->dry_run){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;returnNGX_DECLINED;}r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_DELAYED;if(r->connection->read->ready){ngx_post_event(r->connection->read,&ngx_posted_events);}else{if(ngx_handle_read_event(r->connection->read,0)!=NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}}r->read_event_handler=ngx_http_test_reading;r->write_event_handler=ngx_http_limit_req_delay;r->connection->write->delayed=1;ngx_add_timer(r->connection->write,delay);returnNGX_AGAIN;}
ngx_http_limit_req_handler 函数是 请求频率限制(rate limiting) 的核心处理函数。 它根据配置的限速规则和请求标识(如客户端 IP), 在共享内存中统计请求速率, 并据此决定放行请求、延迟请求(通过异步定时器挂起等待)或立即拒绝请求(返回指定错误码)。 该函数在 `NGX_HTTP_PREACCESS_PHASE` 阶段运行,确保在访问控制前完成流量整形。

2 详解

1 函数签名

staticngx_int_tngx_http_limit_req_handler(ngx_http_request_t*r)
返回值 用于返回函数执行结果的状态码
参数 ngx_http_request_t *r 指向当前 HTTP 请求上下文结构体

2 逻辑流程

1 局部变量 2 防重入校验 3 配置提取 4 初始化 5 遍历所有限速规则 6 所有规则均未命中 7 限流拦截或异常 8 处理需要延迟或放行的情况

1 局部变量
{uint32_thash;ngx_str_tkey;ngx_int_trc;ngx_uint_tn,excess;ngx_msec_tdelay;ngx_http_limit_req_ctx_t*ctx;ngx_http_limit_req_conf_t*lrcf;ngx_http_limit_req_limit_t*limit,*limits;

2 防重入校验
if(r->main->limit_req_status){returnNGX_DECLINED;}
检查主请求状态 如果主请求的 limit_req_status 已被设置, 说明请求已经过本模块处理并得出了最终结果(拒绝、延迟或通过), 直接返回 NGX_DECLINED 表示不再处理。

3 配置提取
lrcf=ngx_http_get_module_loc_conf(r,ngx_http_limit_req_module);limits=lrcf->limits.elts;
lrcf: 从当前请求的 location 配置中取出 ngx_http_limit_req_module 的配置结构。 limits:将配置中存储限速规则的动态数组 (lrcf->limits) 取出为 C 数组指针,便于遍历。

4 初始化
excess=0;rc=NGX_DECLINED;
初始化超出量为 0。 将最终返回值预设为 NGX_DECLINED, 表示“未匹配任何规则,放行”。 后续根据查找结果修改。

#if(NGX_SUPPRESS_WARN)limit=NULL;#endif
抑制编译器警告 如果编译时定义了 NGX_SUPPRESS_WARN(通常用于消除未初始化警告), 则将 limit 显式初始化为 NULL。避免某些编译器在优化时误报 limit 可能未被初始化。

5 遍历所有限速规则
for(n=0;n<lrcf->limits.nelts;n++){limit=&limits[n];ctx=limit->shm_zone->data;if(ngx_http_complex_value(r,&ctx->key,&key)!=NGX_OK){ngx_http_limit_req_unlock(limits,n);returnNGX_HTTP_INTERNAL_SERVER_ERROR;}if(key.len==0){continue;}if(key.len>65535){ngx_log_error(NGX_LOG_ERR,r->connection->log,0,"the value of the \"%V\" key ""is more than 65535 bytes: \"%V\"",&ctx->key.value,&key);continue;}hash=ngx_crc32_short(key.data,key.len);ngx_shmtx_lock(&ctx->shpool->mutex);rc=ngx_http_limit_req_lookup(limit,hash,&key,&excess,(n==lrcf->limits.nelts-1));ngx_shmtx_unlock(&ctx->shpool->mutex);ngx_log_debug4(NGX_LOG_DEBUG_HTTP,r->connection->log,0,"limit_req[%ui]: %i %ui.%03ui",n,rc,excess/1000,excess%1000);if(rc!=NGX_AGAIN){break;}}
循环遍历配置的所有限速规则

6 所有规则均未命中
if(rc==NGX_DECLINED){returnNGX_DECLINED;}
如果最终 rc 仍为 NGX_DECLINED,说明没有任何规则限制此请求,直接放行

7 限流拦截或异常
if(rc==NGX_BUSY||rc==NGX_ERROR){if(rc==NGX_BUSY){ngx_log_error(lrcf->limit_log_level,r->connection->log,0,"limiting requests%s, excess: %ui.%03ui by zone \"%V\"",lrcf->dry_run?", dry run":"",excess/1000,excess%1000,&limit->shm_zone->shm.name);}ngx_http_limit_req_unlock(limits,n);if(lrcf->dry_run){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;returnNGX_DECLINED;}r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_REJECTED;returnlrcf->status_code;}
处理拒绝情况 当返回 NGX_BUSY(请求超限)或 NGX_ERROR(内部错误)时,准备拒绝请求。

8 处理需要延迟或放行的情况
/* rc == NGX_AGAIN || rc == NGX_OK */if(rc==NGX_AGAIN){excess=0;}delay=ngx_http_limit_req_account(limits,n,&excess,&limit);if(!delay){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_PASSED;returnNGX_DECLINED;}ngx_log_error(lrcf->delay_log_level,r->connection->log,0,"delaying request%s, excess: %ui.%03ui, by zone \"%V\"",lrcf->dry_run?", dry run":"",excess/1000,excess%1000,&limit->shm_zone->shm.name);if(lrcf->dry_run){r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;returnNGX_DECLINED;}r->main->limit_req_status=NGX_HTTP_LIMIT_REQ_DELAYED;if(r->connection->read->ready){ngx_post_event(r->connection->read,&ngx_posted_events);}else{if(ngx_handle_read_event(r->connection->read,0)!=NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}}r->read_event_handler=ngx_http_test_reading;r->write_event_handler=ngx_http_limit_req_delay;r->connection->write->delayed=1;ngx_add_timer(r->connection->write,delay);returnNGX_AGAIN;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/3 15:10:20

ESP无按钮自动烧录:基于FTDI DTR/RTS的硬件编程方案

1. 项目概述&#xff1a;告别手动复位&#xff0c;实现ESP的“一键”烧录玩过ESP8266&#xff08;比如经典的ESP-01模块&#xff09;或者ESP32-CAM的朋友&#xff0c;肯定都经历过那个有点“手忙脚乱”的烧录时刻&#xff1a;一手按着开发板上的“Flash”或“GPIO0”按钮不放&a…

作者头像 李华
网站建设 2026/6/3 15:09:31

ComfyUI:重新定义AI创作流程的模块化图形界面引擎

ComfyUI&#xff1a;重新定义AI创作流程的模块化图形界面引擎 【免费下载链接】ComfyUI The most powerful and modular diffusion model GUI, api and backend with a graph/nodes interface. 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI 在当今AI内容创…

作者头像 李华
网站建设 2026/6/3 15:05:57

智慧职教刷课脚本终极指南:3步告别手动学习烦恼

智慧职教刷课脚本终极指南&#xff1a;3步告别手动学习烦恼 【免费下载链接】auto-play-course 简单好用的刷课脚本[支持平台:职教云,智慧职教,资源库] 项目地址: https://gitcode.com/gh_mirrors/hc/auto-play-course 还在为智慧职教平台的繁琐学习任务而烦恼吗&#x…

作者头像 李华
网站建设 2026/6/3 15:02:41

Deepoc VLA开发板:无人机群体协同与无网络自主作业核心

当前无人机在拓展其应用边界时&#xff0c;面临两大体系性瓶颈&#xff1a;多机集群的智能协同效率低下&#xff0c;以及在通信拒止环境下的作业能力中断。传统以地面站为中心的集中式控制与决策模式&#xff0c;难以满足上述场景对实时性、鲁棒性与自主性的苛刻要求。Deepoc具…

作者头像 李华