使用nginx_http_mirror_module时,limit_except GET为何无法拦截PURGE请求?
问题原因分析:Nginx镜像规则意外转发PURGE请求
配置回顾
HTTP块配置:
split_clients "${remote_addr}AAA" $mirror_backend { 30% web_mirror; * ""; }
Server块配置:
location / { gunzip on; include /etc/nginx/proxy_params; mirror /mirror; proxy_pass http://varnish; } location = /mirror { internal; limit_except GET { deny all; } if ($mirror_backend = "") { return 400; } include /etc/nginx/proxy_params; proxy_pass http://$mirror_backend$request_uri; }
镜像端异常日志:
10.0.0.10 mydomain.com 2023-10-25T14:51:52+02:00 "PURGE /path/here HTTP/1.1" 405 0 "-" "cache-warmer/android" - "-" - - - - 99cae641-0961-48b3-9965-bfd4a8ed3ff7 0.091 - - - - ruby
核心原因:指令执行阶段优先级冲突
Nginx的请求处理分为多个阶段,rewrite阶段(包含if指令)的执行顺序早于access阶段(包含limit_except指令):
mirror /mirror会原样复制原请求的HTTP方法(包括PURGE)发送到内部/mirrorlocation- 进入
/mirrorlocation后,先执行rewrite阶段的if ($mirror_backend = "")判断:- 当请求命中30%的分流规则时,
$mirror_backend不为空,不会触发return 400,而是直接执行后续的proxy_pass完成转发
- 当请求命中30%的分流规则时,
- 整个请求处理流程在rewrite阶段就已结束,完全跳过了access阶段的
limit_except GET规则,导致PURGE请求被意外转发到镜像端
额外触发条件:镜像指令的无差别复制特性
mirror指令不会主动过滤请求方法,只要主location接收了PURGE请求,就会生成对应的镜像请求发送到/mirror location,而主location中未添加对PURGE请求的镜像拦截规则,这是问题发生的前提。
内容的提问来源于stack exchange,提问作者Niels Kristian
相关产品推荐
相关产品推荐

