1 定义ngx_http_limit_req_handler 函数 定义在 ./nginx-1.24.0/src/http/modules/ngx_http_limit_req_module.cstaticngx_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;}lrcfngx_http_get_module_loc_conf(r,ngx_http_limit_req_module);limitslrcf-limits.elts;excess0;rcNGX_DECLINED;#if(NGX_SUPPRESS_WARN)limitNULL;#endiffor(n0;nlrcf-limits.nelts;n){limitlimits[n];ctxlimit-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.len0){continue;}if(key.len65535){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;}hashngx_crc32_short(key.data,key.len);ngx_shmtx_lock(ctx-shpool-mutex);rcngx_http_limit_req_lookup(limit,hash,key,excess,(nlrcf-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(rcNGX_DECLINED){returnNGX_DECLINED;}if(rcNGX_BUSY||rcNGX_ERROR){if(rcNGX_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_statusNGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;returnNGX_DECLINED;}r-main-limit_req_statusNGX_HTTP_LIMIT_REQ_REJECTED;returnlrcf-status_code;}/* rc NGX_AGAIN || rc NGX_OK */if(rcNGX_AGAIN){excess0;}delayngx_http_limit_req_account(limits,n,excess,limit);if(!delay){r-main-limit_req_statusNGX_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_statusNGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;returnNGX_DECLINED;}r-main-limit_req_statusNGX_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_handlerngx_http_test_reading;r-write_event_handlerngx_http_limit_req_delay;r-connection-write-delayed1;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 配置提取lrcfngx_http_get_module_loc_conf(r,ngx_http_limit_req_module);limitslrcf-limits.elts;lrcf 从当前请求的 location 配置中取出 ngx_http_limit_req_module 的配置结构。 limits将配置中存储限速规则的动态数组 (lrcf-limits) 取出为 C 数组指针便于遍历。4 初始化excess0;rcNGX_DECLINED;初始化超出量为 0。 将最终返回值预设为 NGX_DECLINED 表示“未匹配任何规则放行”。 后续根据查找结果修改。#if(NGX_SUPPRESS_WARN)limitNULL;#endif抑制编译器警告 如果编译时定义了 NGX_SUPPRESS_WARN通常用于消除未初始化警告 则将 limit 显式初始化为 NULL。避免某些编译器在优化时误报 limit 可能未被初始化。5 遍历所有限速规则for(n0;nlrcf-limits.nelts;n){limitlimits[n];ctxlimit-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.len0){continue;}if(key.len65535){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;}hashngx_crc32_short(key.data,key.len);ngx_shmtx_lock(ctx-shpool-mutex);rcngx_http_limit_req_lookup(limit,hash,key,excess,(nlrcf-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(rcNGX_DECLINED){returnNGX_DECLINED;}如果最终 rc 仍为 NGX_DECLINED说明没有任何规则限制此请求直接放行7 限流拦截或异常if(rcNGX_BUSY||rcNGX_ERROR){if(rcNGX_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_statusNGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;returnNGX_DECLINED;}r-main-limit_req_statusNGX_HTTP_LIMIT_REQ_REJECTED;returnlrcf-status_code;}处理拒绝情况 当返回 NGX_BUSY请求超限或 NGX_ERROR内部错误时准备拒绝请求。8 处理需要延迟或放行的情况/* rc NGX_AGAIN || rc NGX_OK */if(rcNGX_AGAIN){excess0;}delayngx_http_limit_req_account(limits,n,excess,limit);if(!delay){r-main-limit_req_statusNGX_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_statusNGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;returnNGX_DECLINED;}r-main-limit_req_statusNGX_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_handlerngx_http_test_reading;r-write_event_handlerngx_http_limit_req_delay;r-connection-write-delayed1;ngx_add_timer(r-connection-write,delay);returnNGX_AGAIN;}