map指令仅做变量映射,不操作缓冲区;通过提取$uri等路径特征生成服务名、缓存策略等标签,再由proxy_cache、proxy_pass等指令协同实现动态分发与缓存控制。

map 指令本身不操作缓冲区,也不直接控制缓存行为;它只做变量映射。所谓“结合缓冲区实现路径动态分发”,本质是用 map 提取路径特征生成逻辑标签(如服务名、缓存策略、后端集群),再由 proxy_cache、proxy_pass 等指令协同完成流量分发与缓存控制。
从请求路径提取关键维度
map 的输入必须是字符串型变量,$uri 或 $request_uri 是最常用源。注意二者区别:$uri 是解码后、标准化的路径(不含查询参数),适合做精确路由;$request_uri 保留原始编码和参数,适合需透传完整路径的场景。
- 提取一级路径作为服务标识:
map $uri $service {
~^/api/v1/users/ "users-v1";
~^/api/v1/orders/ "orders-v1";
~^/static/ "cdn-static";
default "default-svc";
} - 避免正则冲突:匹配顺序从上到下,长路径需放前面(如 /api/v1/users/ 要在 /api/v1/ 前),否则会被更宽泛规则截断
- 不建议用 $request_uri 做缓存 key 主体——含参数易导致缓存碎片化;如需区分参数,应单独用 map 提取特定 arg(如 $arg_version)再组合
用 map 驱动缓存策略与回源目标
一个路径可能同时决定“去哪台后端”和“怎么缓存”。这两个决策可由不同 map 并行完成,再在 location 中组合使用:
- 定义缓存区域名:
map $uri $cache_zone {
~^/static/ "static_zone";
~^/api/v1/(users|orders)/ "api_v1_zone";
default "no_cache_zone";
} - 定义缓存 key 构造方式(影响命中率):
map $uri $cache_key {
~^/static/ "$host$uri";
~^/api/v1/users/ "$host$uri$arg_user_id";
default "$host$uri";
} - 对应 upstream 必须提前声明,名称与 map 输出值严格一致:
upstream users-v1 { server 10.0.2.10:8080; }
upstream orders-v1 { server 10.0.2.11:8080; }
在 location 中落地分发与缓存逻辑
map 只生成变量,真正起作用的是后续指令。典型配置结构如下:
- 启用缓存模块(需在 http 块中已定义 proxy_cache_path):
proxy_cache $cache_zone;
proxy_cache_key $cache_key;
proxy_cache_valid 200 302 10m; - 动态转发到对应 upstream:
proxy_pass http://$service; - 若需强制跳过缓存(如带特定 header 的调试请求),可用另一个 map 控制 proxy_cache_bypass:
map $http_x_no_cache $cache_bypass { "1" "1"; default ""; } - 注意 proxy_pass 后不能加路径(如 http://$service/),否则会覆盖原始 URI;如需重写路径,用 rewrite 或 proxy_redirect
常见问题与避坑点
- map 必须写在 http 块顶层,server 或 location 内无效
- $service 等变量输出值必须与 upstream 名完全一致,包括大小写和符号(支持下划线,不支持短横线)
- 正则匹配要加引号和 ~ 前缀,如 "~^/api/";不加 ~ 就是纯字符串匹配
- 所有 map 必须设 default 分支,否则未匹配时变量为空,可能导致 502 或配置解析失败
- 缓存 key 中慎用 $request_body —— 它在 proxy_pass 之后才可读,且仅对 POST/PUT 生效,容易引发 400 或缓存错乱

















