You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx 1.24.0动态模块Handler回调被调用两次导致IP提前封禁问题

Nginx 1.24.0动态模块Handler回调被调用两次导致IP提前封禁问题

嘿,我之前做Nginx模块开发时也踩过一模一样的坑,太懂那种明明设置了20次限制结果10次就被封的憋屈了!咱们来好好捋捋为什么你的handler会被调用两次:

最容易踩的几个坑:

  • 子请求触发
    Nginx处理某些请求时会自动发起内部子请求,比如开了autoindex on访问目录、用了SSI、或者rewrite模块触发的内部重定向,都会产生子请求。要是你的模块挂载到了NGX_HTTP_CONTENT_PHASE这类会被子请求执行的阶段,主请求和子请求都会触发handler,相当于一次外部请求被计数两次。

你可以在handler里加个判断,跳过子请求的统计:

if (r->internal) {
    return NGX_DECLINED; // 子请求直接跳过计数逻辑
}

这样就只会统计真实的外部请求啦。

  • 模块挂载阶段选错
    要是你把handler注册到了NGX_HTTP_PRECONTENT_PHASE或者更早的阶段,可能会因为Nginx请求流程里的某些操作(比如rewrite重定向、URI修正)导致该阶段被重复执行。比如rewrite修改了请求URI后,Nginx会重新走一遍部分处理阶段,你的handler自然就被调用第二次了。

对于IP访问计数这类需求,更推荐挂载到NGX_HTTP_ACCESS_PHASE——这个阶段是Nginx专门用来做访问控制的,只会执行一次,而且在内容处理前就能拦截违规请求,逻辑更合理。

  • 配置重复注册handler
    要是你在模块的配置解析逻辑里,不小心把handler注册了两次(比如同时在http块和server块都注册了同一个handler实例),那每个请求就会被两个handler各处理一次,计数直接翻倍。可以检查下你的ngx_http_module_t结构体里的配置钩子,看看是不是重复添加了handler注册的逻辑。

  • HEAD请求的特殊情况
    这种情况相对少见,但Nginx处理HEAD请求时,会先像GET请求一样执行handler,再去掉响应体返回。不过一般Nginx会保证handler只调用一次,但如果你的代码里对HEAD请求做了特殊分支处理,可能会不小心触发重复计数,也可以排查下这块逻辑。

快速排查小妙招

你可以在handler里加一行调试日志,打印请求的URI和是否为内部子请求的标记:

ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
              "Handler triggered: uri=%V, internal=%d",
              &r->uri, r->internal);

然后打开Nginx的debug日志(编译时要加--with-debug参数,配置文件里设置error_log logs/error.log debug;),看看每次触发的请求详情,就能快速定位到底是子请求还是阶段重复执行的问题啦!

备注:内容来源于stack exchange,提问作者tyxWilliam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 16:48:20