Nginx在处理请求时会自动解析Cookie请求头,并把每个Cookie项拆分成同名变量。访问某个Cookie的值不需要写正则或调用Lua,只要按照固定前缀加Cookie名的方式引用变量即可。这套变量在访问日志、rewrite、access阶段都可以直接使用,但要注意变量懒加载和请求阶段限制。

$cookie_*变量的生成规则与基础读取
Nginx为每个请求头里的Cookie项创建一个以$cookie_为前缀的变量。Cookie名称会直接拼在$cookie_后面,例如请求头是Cookie: session_id=abc123,那么在Nginx配置里就可以通过$cookie_session_id拿到abc123。这个映射关系在解析请求头时自动完成,不需要额外配置。
这里有一个关键细节:$cookie_后面的变量名是区分大小写的。如果客户端发送的是Cookie: UserID=1,那么$cookie_UserID可以取到值,写成$cookie_userid则会返回空字符串。实际项目中建议统一使用小写Cookie名,避免因为大小写不一致导致配置失效。可以通过浏览器开发者工具或curl命令查看请求头中Cookie名的原始大小写,确保配置中的变量名与之一致。
基础读取示例:在日志中记录名为session_id的Cookie值,可以这样配置。
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$cookie_session_id"';
access_log /var/log/nginx/access.log main;
上面配置中$cookie_session_id会输出请求头里session_id的值,如果不存在则输出空。需要注意,如果Cookie值中包含空格、分号或双引号,日志格式可能会被截断或错位,因此记录敏感Cookie时最好做清洗或URL编码处理。
用map和if指令做Cookie条件判断
除了直接读取变量,更多场景需要根据Cookie值执行不同逻辑。例如做登录校验时,判断auth_token是否为空;做灰度发布时,根据user_group的值路由到不同后端。Nginx的if指令可以完成简单判断,但官方文档并不推荐过度使用if,尤其是if与rewrite模块混用时可能出现预期外的行为。
对于需要提取Cookie中某个值进行映射或判断的场景,map指令是更安全的选择。map在Nginx启动阶段定义映射关系,运行阶段只做查表,不会引入if的副作用。下面示例通过$cookie_user_group将用户分组映射到不同后端主机。
map $cookie_user_group $backend {
default 10.0.0.1:8080;
vip 10.0.0.2:8080;
test 10.0.0.3:8080;
}
server {
listen 80;
location / {
proxy_pass http://$backend;
}
}
如果Cookie名包含连字符或点号,比如user-id,Nginx变量名无法包含连字符,此时$cookie_user-id会被解析为$cookie_user减去id,不能正常读取。这种情况下可以改用map配合$http_cookie进行正则提取。
map $http_cookie $user_id {
default "";
~*user-id=([^;]+) $1;
}
这份配置会从整个Cookie头中抓取user-id对应的值。注意正则里的分号需要根据实际Cookie分隔规则调整,如果Cookie值本身经过URL编码,提取到的也是编码后的字符串。与直接使用$cookie_变量相比,这种方式在解析效率和可读性上略差,但能覆盖特殊字符场景。
典型应用场景:访问控制、灰度发布与缓存策略
访问控制是$cookie_变量最常用的场景之一。假设只有携带有效auth_token的请求才能访问内部接口,可以这样写:
location /internal/ {
if ($cookie_auth_token = "") {
return 302 /login;
}
proxy_pass http://backend_service;
}
这种方式只能做简单的空值判断,不能验证Token是否合法。如果需要对Token做签名校验或查询数据库,建议在Nginx后端的应用层完成,或者使用OpenResty的resty.jwt等库。Nginx层的判断适合做快速拦截,减少非法请求打到应用服务器的数量。
灰度发布同样是高频需求。通过给用户分组并写入Cookie,再配合map将不同组路由到不同版本的服务,就能实现小流量验证。下面配置根据Cookie中的canary值决定是否走新版本:
map $cookie_canary $upstream_pool {
default stable_pool;
~*on canary_pool;
}
upstream stable_pool {
server 10.0.1.10:8080;
}
upstream canary_pool {
server 10.0.1.20:8080;
}
server {
listen 80;
location / {
proxy_pass http://$upstream_pool;
}
}
缓存策略也可以根据Cookie动态调整。例如当请求头里存在nocache=1时,强制不命中缓存,让请求穿透到源站。这个需求用一条proxy_cache_bypass就能实现:
location /api/ {
proxy_cache my_cache;
proxy_cache_bypass $cookie_nocache;
proxy_pass http://backend_api;
}
$cookie_nocache的值只有为空或0时才不影响缓存,其他非空值都会触发绕过缓存。这正是Nginx内置变量的便利之处,不用单独写if判断。
安全注意事项与使用边界
从安全角度看,$cookie_变量读取的是客户端原始输入,值完全不可信。不要将Cookie值直接拼接到系统命令、SQL语句或文件路径中。即使在Nginx配置里用于proxy_pass目标,也必须先通过map将可能的值限定在白名单内,不能直接使用$cookie_backend作为上游地址,否则攻击者可以通过构造Cookie将请求转发到任意内网地址。
另一个容易忽略的问题是URL编码。Nginx的$cookie_变量返回的值不会自动进行URL解码,也就是说客户端发送Cookie: token=a%20b,$cookie_token得到的就是a%20b而不是a b。如果后端期望解码后的值,需要在应用层处理,或者使用Nginx的set配合第三方解码模块,但原生配置中没有直接解码Cookie值的指令。
还需要注意Cookie值的长度和特殊字符。Nginx变量可以容纳较长的字符串,但日志系统、下游应用可能存在长度限制。含有换行符或控制字符的Cookie会污染访问日志,甚至造成日志格式注入。在打印日志前最好对变量进行过滤,或者直接避免记录完整Cookie值。
性能方面,$cookie_变量是按需读取的,只有在配置中实际引用时才会解析对应Cookie。因此使用单个变量不会带来明显开销,但如果在map中匹配$http_cookie并写复杂正则,则每个请求都要完整解析Cookie头,高并发下会有可测量的CPU消耗。合理设计Cookie命名和引用方式,既能保证可读性,也能控制性能损失。
Nginx Cookie变量Cookie读取Nginx配置修改时间:2026-09-20 18:20:05