- 后端
- 网络/通信
- 云原生
【免费下载链接】bfe
A modern layer 7 load balancer from baidu
mod_header.data是 BFE(百度自研的七层负载均衡器)中mod_header模块的规则配置文件,用于按产品(product)维度定义请求头、响应头以及 Cookie 的增删改查动作。本文以该文件为骨架,结合仓库源码(bfe_modules/mod_header/与conf/mod_header/)深入讲解其配置结构、全部模块动作、参数校验规则、变量插值机制与热加载原理,读完即可独立编写并校验一套可上线的 header 规则。
一、文件定位与作用
mod_header是 BFE 内置的 HTTP 头部处理模块,它在请求被路由定位之后(HandleAfterLocation)与响应返回之前(HandleReadResponse)分别注入过滤器,对进出流量做头部改写(见 mod_header.go)。
与模块相关的配置分为两层:
| 文件 | 作用 | 仓库示例 |
|---|---|---|
mod_header.conf | 模块基础配置:规则文件路径、是否禁用默认头、调试日志开关 | conf/mod_header/mod_header.conf |
mod_header.data | 模块规则配置:按产品定义 header/cookie 动作(本文主题) | conf/mod_header/header_rule.data |
注意:
mod_header.conf中Basic.DataPath默认指向mod_header/mod_header.data(见 conf_mod_header.go),实际部署时可指向任意文件名(仓库默认配置即为mod_header/header_rule.data)。
二、配置结构与字段说明
mod_header.data是一个 JSON 文件,顶层结构为{ "Version": ..., "Config": { "<产品名>": [规则列表] } }。各字段含义如下:
| 配置项 | 类型 | 含义 | 是否必填 | 补充说明 | 生效条件 |
|---|---|---|---|---|---|
Version | String | 配置文件版本号 | 是 | 通常为时间戳,如20190101000000;类型定义见 00-common.md#5-version | 类型必须符合 Version 定义 |
Config | Object | 各产品的 header 规则 | 是 | Key 为产品名 | - |
Config{k} | String | 产品名 | 是 | - | - |
Config{v} | Array | 该产品的 header 规则列表 | 是 | - | - |
Config{v}[] | Object | 单条 header 规则 | 是 | - | - |
Config{v}[].Cond | String | 规则匹配条件 | 是 | 语法见 condition_grammar.md | 必须是合法的 Condition 表达式 |
Config{v}[].Last | Boolean | 匹配后是否停止执行后续规则 | 否 | 默认false | - |
Config{v}[].Actions | Array | 匹配后要执行的动作列表 | 是 | - | - |
Config{v}[].Actions[].Cmd | String | 动作名称 | 是 | 取值见下文"模块动作" | - |
Config{v}[].Actions[].Params | Array | 动作参数列表 | 否 | 参数个数与含义随动作而定,元素类型为 String | - |
源码中与之一一对应的数据结构定义在 header_rule_load.go:HeaderRuleFile(Cond/Actions/Last)、HeaderConfFile(Version/Config),以及加载后的运行时结构HeaderRule/HeaderConf。
规则级校验(HeaderRuleCheck)
HeaderConfLoad在解码 JSON 后会先做整体校验(header_rule_load.go),随后逐产品、逐规则调用HeaderRuleCheck(header_rule_load.go):
Cond为空 → 报错no Cond;Actions为空(nil 或空切片)→ 报错no Actions;- 任一 Action 非法 → 报错并携带索引,如
Actions:<err>; Last未设置 → 报错no Last。
对应测试用例见 header_rule_load_test.go,其中构造了abnormalTypeNilCondition、abnormalTypeNilActions、abnormalTypeEmptyActions、abnormalTypeNilLast四类异常场景验证报错逻辑。
三、模块动作(Actions)详解
mod_header共提供 13 个动作,覆盖请求头、响应头、请求 Cookie、响应 Cookie 四个方向。参数个数与格式在加载期即被严格校验(见 action.go 的ActionFileCheck)。
| 动作 | 说明 | 参数 | 参数要求(源码校验) |
|---|---|---|---|
REQ_HEADER_SET | 设置请求头(已存在则覆盖) | HeaderName, HeaderValue | 必须 2 个 |
REQ_HEADER_ADD | 追加请求头(不覆盖已有值) | HeaderName, HeaderValue | 必须 2 个 |
REQ_HEADER_DEL | 删除请求头 | HeaderName | 必须 1 个 |
REQ_HEADER_RENAME | 重命名请求头 | OriginalHeaderName, NewHeaderName | 必须 2 个 |
RSP_HEADER_SET | 设置响应头 | HeaderName, HeaderValue | 必须 2 个 |
RSP_HEADER_ADD | 追加响应头 | HeaderName, HeaderValue | 必须 2 个 |
RSP_HEADER_DEL | 删除响应头 | HeaderName | 必须 1 个 |
RSP_HEADER_RENAME | 重命名响应头 | OriginalHeaderName, NewHeaderName | 必须 2 个 |
REQ_HEADER_MOD | 修改请求头(scheme_set / query_add) | scheme_set/query_add, HeaderName, ... | 3 或 4 个,见下 |
RSP_HEADER_MOD | 修改响应头(scheme_set / query_add) | scheme_set/query_add, HeaderName, ... | 3 或 4 个,见下 |
REQ_COOKIE_SET | 设置请求 Cookie | CookieName, CookieValue | 必须 2 个 |
REQ_COOKIE_DEL | 删除请求 Cookie | CookieName | 必须 1 个 |
RSP_COOKIE_SET | 设置响应 Cookie | Name, Value, Domain, Path, Expires(RFC1123), MaxAge(int), HttpOnly(bool), Secure(bool) | 必须 8 个且类型正确 |
RSP_COOKIE_DEL | 删除响应 Cookie | Name, Domain, Path | 必须 3 个 |
除个数校验外,还有几类更细化的约束:
- 任意参数为空串即报错(
empty Params),见 action.go; - Cookie 类型强校验:
RSP_COOKIE_SET的Expires必须能被time.Parse(time.RFC1123, ...)解析,MaxAge必须为整数,HttpOnly/Secure必须为布尔串,否则加载失败(action.go); - 未识别的 Cmd 直接报错
invalid cmd:%s(action.go)。
REQ/RSP_HEADER_MOD 的两种子命令
REQ_HEADER_MOD与RSP_HEADER_MOD不是简单的"覆盖",而是对头部值做结构化改写(action.go 的checkHeaderModParams与 action.go 的modHeaderValue):
scheme_set:改写 URL 的协议头。- 参数:
[scheme_set, HeaderName, scheme],共 3 个; - 仅支持
Referer/Location两个头部; scheme仅允许http/https;- 底层实现
setScheme只替换http:///https://前缀后的 scheme 部分(action.go)。 - 典型场景:
["scheme_set", "Location", "https"]将 301 跳转的 Location 强制改为 https。
- 参数:
query_add:在 URL 中追加 query 参数。- 参数:
[query_add, HeaderName, key, value],共 4 个; - 同样仅支持
Referer/Location; - 底层实现
addQuery解析 URL 后追加key=value,已有 query 时用&拼接(action.go)。
- 参数:
注意:
HEADER_MOD只在目标头部已存在且值非空时才生效;若头部不存在则直接跳过(action.go)。
四、动作的底层实现
所有 header 类动作最终收敛到 4 个原子操作(action_header.go):
| 底层函数 | 行为 | 对应动作 |
|---|---|---|
headerSet | h.Set(key, value):插入或覆盖 | SET |
headerAdd | h.Add(key, value):追加(保留多值) | ADD |
headerDel | h.Del(key):删除 | DEL |
headerRename | 先读原值Set(newKey, val)再Del(originalKey) | RENAME |
processHeader会把动作前缀REQ_/RSP_裁掉后分发到HeaderActionDo(action.go),并自动用textproto.CanonicalMIMEHeaderKey规范化头部名(如x-bfe-vip→X-Bfe-Vip)。RENAME在目标新头部已存在或原头部不存在时会跳过,避免覆盖已有值。
Cookie 动作的实现见 action_cookie.go:请求 Cookie 的 SET/DEL 会重建整个Cookie头并同步req.CookieMap;响应 Cookie 通过操作Set-Cookie头实现,SET 与 DEL 都会以(Name, Path, Domain)三元组判断目标 Cookie 是否存在,存在才覆盖/删除。
五、Header 值变量插值
动作参数值支持两种特殊写法(见 action.go 的preProcessParams与 action.go 的getHeaderValue):
%变量名:运行时替换为当前请求的对应信息;%%变量名:转义为字面量%变量名(不做替换)。
可用的变量(注册于 action_header_var.go 的VariableHandlers映射)按类别整理如下:
| 类别 | 变量 |
|---|---|
| 客户端信息 | bfe_client_ip、bfe_client_port、bfe_cip(client ip 别名)、bfe_request_host |
| 连接与会话 | bfe_session_id、bfe_log_id、bfe_vip(虚拟 IP)、bfe_bip(负载均衡器 IP)、bfe_rip(BFE 本机 IP)、bfe_server_name |
| 后端信息 | bfe_cluster、bfe_backend_info(格式ClusterName:..,SubClusterName:..,BackendName:..(addr)) |
| TLS/协议 | bfe_ssl_resume、bfe_ssl_cipher、bfe_ssl_version、bfe_ssl_ja3_raw、bfe_ssl_ja3_hash、bfe_protocol、bfe_http2_fingerprint |
| 客户端证书 | client_cert_serial_number、client_cert_subject_title、client_cert_subject_common_name、client_cert_subject_organization、client_cert_subject_organizational_unit、client_cert_subject_province、client_cert_subject_country、client_cert_subject_locality |
| 地理信息(依赖 mod_geo) | bfe_client_geo_country_iso_code、bfe_client_geo_subdivision_iso_code、bfe_client_geo_city_name、bfe_client_geo_latitude、bfe_client_geo_longitude |
一个参数值中还可以混合普通文本与变量(如"__bsi=%bfe_ssl_info;max-age=3600"),splitParam会将其切分为多个片段再拼接(action.go)。若%后跟的变量名未注册,加载期即报错。
六、完整配置示例
原文档给出的完整示例(路径前缀为/header时,注入请求头X-Bfe-Log-Id、X-Bfe-Vip,并给响应加X-Proxied-By: bfe,且匹配后停止后续规则):
{ "Version": "20190101000000", "Config": { "example_product": [ { "cond": "req_path_prefix_in(\"/header\", false)", "actions": [ { "cmd": "REQ_HEADER_SET", "params": [ "X-Bfe-Log-Id", "%bfe_log_id" ] }, { "cmd": "REQ_HEADER_SET", "params": [ "X-Bfe-Vip", "%bfe_vip" ] }, { "cmd": "RSP_HEADER_SET", "params": [ "X-Proxied-By", "bfe" ] } ], "last": true } ] } }仓库自带的默认配置见 conf/mod_header/header_rule.data(对example_product的/header路径设置响应头X-Proxied-By: bfe),对应的基础配置文件为 conf/mod_header/mod_header.conf,其中DataPath = mod_header/header_rule.data指向规则文件。
更多实用写法
- 按域名/条件区分处理:
cond可写任意合法 Condition,如req_host_in("example.com")、req_path_prefix_in("/api", true)、req_tag_in("tag1")等,语法参考 condition_grammar.md; - 一条规则多动作:
Actions数组内按顺序执行,如先REQ_HEADER_DEL再REQ_HEADER_ADD; - 同值多头部:
REQ_HEADER_ADD用于保留多值场景,REQ_HEADER_SET用于覆盖场景。
七、匹配执行逻辑与 Last 语义
mod_header对每个产品维护两张规则表(请求方向/响应方向),由classifyRules依据动作前缀REQ_/RSP_在加载期拆分(header_rule_load.go)。
运行时匹配逻辑位于DoHeader(mod_header.go):
for _, rule := range *ruleList { if rule.Cond.Match(req) { HeaderActionsDo(req, headerType, rule.Actions) if rule.Last { break // 停止执行后续规则 } } }即:规则按数组顺序依次求值,命中则执行其全部动作;Last: true时命中后立即跳出,不再评估后面的规则(默认false继续向后匹配)。这与主流网关的"首匹配 + 短路"策略一致,可用来做"先特殊后兜底"的分层规则。
执行顺序上还有一个重要细节(mod_header.go):
- 先应用产品名为
global(常量GlobalProduct)的全局规则; - 再应用当前产品
request.Route.Product的专属规则; - 因此产品专属规则的 HEADER_SET 会覆盖 global 规则设置的同一头部,而 ADD 动作则会叠加。
另外,请求方向处理时若DisableDefaultHeader未开启,模块还会先写入默认头(X-Forwarded-For、X-Real-IP等),其开关见 mod_header.conf 文档。
八、加载、校验与热更新
加载流程
HeaderConfLoad(filename)的完整链路(header_rule_load.go):
- 打开并解码 JSON 文件;
HeaderConfCheck校验 Version/Config 存在;ProductRulesCheck→RuleListCheck→HeaderRuleCheck逐层校验;ruleConvert用condition.Build(cond)把 Condition 字符串编译为可执行的condition.Condition,并把ActionFile转换为运行时Action(含头部名规范化、参数预处理);classifyRules按请求/响应方向拆表,存入ProductRules。
热更新机制
mod_header在初始化时注册了web_monitor.WebHandleReload回调(mod_header.go),因此可通过 BFE 的 Web Monitor 接口触发loadConfData重新加载规则文件(mod_header.go)。加载成功后调用HeaderTable.Update整体替换规则表,读路径使用读写锁保护(header_table.go),支持无中断热更新——这是线上流量场景下调整 header 策略的标准手段。
校验兜底
规则文件的合法性在加载期已被完整校验(Cond、Actions、Last、参数个数、Cookie 类型、变量名、scheme_set/query_add的约束等),任何一项不满足都会导致加载失败并返回带上下文的错误信息(如HeaderRule:0, Actions:...),配合mod_header.conf中的Log.OpenDebug可输出请求改写前后的完整头部对比日志。
九、小结
围绕mod_header.data,本文完整覆盖了:
- 配置骨架:
Version+Config{产品: [规则]},以及Cond/Last/Actions的语义与必填约束; - 13 个动作:请求/响应头与 Cookie 的 SET/ADD/DEL/RENAME/MOD,含参数个数与类型校验;
- 变量插值:
%bfe_log_id、%bfe_vip等 30+ 内置变量; - 运行机制:global 优先、产品覆盖、
Last短路、按 REQ/RSP 方向拆表执行; - 运维能力:加载校验 + Web Monitor 热更新。
如需进一步了解模块基础配置,可阅读 mod_header.conf 文档;规则 Condition 的完整语法见 condition_grammar.md。生产环境建议先在 tests/integration 的测试样例中验证规则行为,再通过热更新接口灰度上线。
- 后端
- 网络/通信
- 云原生
【免费下载链接】bfe
A modern layer 7 load balancer from baidu
相关推荐
BFE mod_header 模块实战指南:基于条件规则的请求/响应头部与 Cookie 管理
BFE mod_header 模块实战指南:基于条件规则的请求/响应头部与 Cookie 管理 导读 mod_header 是 BFE(Baidu Front
后端网络/通信云原生RocketRide Helm Chart 部署指南:Kubernetes 安装配置、Secret 管理与共享存储校验下的高可用扩缩实践
RocketRide Helm Chart 部署指南:Kubernetes 安装配置、Secret 管理与共享存储校验下的高可用扩缩实践 本文基于 Rocket
后端网络/通信云原生fast_align 性能优化实战:无监督词对齐的多核并行与 tcmalloc 加速
fast_align 性能优化实战:无监督词对齐的多核并行与 tcmalloc 加速 当平行语料达到百万句对规模,fast_align(一款轻量的无监督词对齐工
后端网络/通信云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考