nginx请求上下文是每个请求与模块独享的内存结构体,用于异步处理中保存动态状态;它在请求初始化时从r->pool分配,通过ngx_http_set_ctx存入r->ctx[],由ngx_http_get_module_ctx获取,随内存池自动销毁。

Nginx 处理请求时,上下文不是全局共享的“环境变量”,而是为每个请求、每个模块单独分配的一块内存结构体,用于在异步处理过程中暂存中间状态。
每个请求+每个模块都有独立上下文
Nginx 是全异步事件驱动模型,一个 HTTP 请求可能被多次调度——比如先经过 rewrite 模块,再进 access 模块,又到 proxy 模块,最后由 log 模块收尾。这些模块不会连续执行,中间可能穿插成百上千次 epoll 事件轮询。因此,模块无法依赖局部变量或静态变量保存状态,必须把当前处理进度、临时数据等写入专属于该请求、该模块的上下文结构体中。
- 上下文结构体在请求初始化阶段,从该请求专属的内存池(r->pool)中分配
- 结构体指针通过宏 ngx_http_set_ctx(r, ctx, module) 存入请求对象的 r->ctx[] 数组对应位置
- 后续任意阶段调用 ngx_http_get_module_ctx(r, module) 即可取出,无需重新构造
- 请求结束时,整个内存池释放,上下文自动销毁,无需手动清理
上下文与配置上下文是两回事
容易混淆的是“请求上下文”(request context)和“配置上下文”(configuration context,如 http/server/location 块)。前者是运行时每个请求携带的私有数据容器;后者是编译期解析 nginx.conf 时生成的层级化配置结构(main_conf / srv_conf / loc_conf),用于控制行为策略。
- 配置上下文决定“是否启用缓存”“缓存 key 怎么算”,属于静态策略
- 请求上下文记录“这次请求是否已重写过 URI”“当前用户 session ID 是什么”,属于动态状态
- 两者协同:比如某个模块在 location 中读取 $cookie_sessionid,再把它存进自己的请求上下文中,供后续子请求复用
不设置上下文也没问题
上下文是按需使用的机制。如果某个模块逻辑简单、无状态、单次完成(例如只做日志打点或简单 header 注入),完全可以跳过创建和设置上下文这一步。
- 模块开发者只需在需要跨阶段保值时,才定义结构体、实现 create_loc_conf(或对应配置回调)、并在 handler 中调用 set/get 宏
- 框架不强制要求每个模块都用上下文,也不维护它——完全由模块自己管理生命周期
- 未设置时 ngx_http_get_module_ctx 返回 NULL,模块应据此做空检查
典型使用模式
一个常见实践是:模块首次处理请求时检测上下文为空,就分配并初始化;后续再进入时直接复用。
- 例如限流模块在第一次进入时,根据 $remote_addr 初始化计数器结构体并存入上下文
- 后续同一请求再次触发该模块(如内部子请求),可直接读取并更新该计数器
- 若请求中途出错或超时,上下文随内存池一并释放,不留残留











