等了两年,Cloudflare 终于给规则引擎加上了通配符

有些功能,不是技术上难,而是做对了才算真难。

通配符(Wildcard)匹配就是这样。它的概念简单得不能再简单------用一个 * 号代表"任意内容"------但要在一个服务数千万域名的规则引擎里把它做对,背后藏着一连串工程上的权衡。

2024 年 8 月,Cloudflare 在 Ruleset Engine 全系列产品上正式上线了通配符支持,并把自研的 wildcard 库作为开源 crate 发布。

这篇文章把这件事从头到尾讲清楚。

原文链接:https://blog.cloudflare.com/wildcard-rules/

wildcard crate:https://crates.io/crates/wildcard

开源仓库:https://github.com/cloudflare/wildcard


先说通配符是什么

通配符模式匹配里,* 表示"匹配任意内容,包括空内容"。

一个单独的模式 https://example.com/*/t*st,可以同时覆盖:

  • https://example.com/en/test
  • https://example.com/images/toast
  • https://example.com/blog/trust

每个 * 捕获的内容,可以用 ${1}${2} 这样的语法在目标表达式里引用。这在 URL 重定向里尤其有用:

复制代码
源 URL 模式:https://example.com/*/t*st
目标 URL:   https://${1}.example.com/t${2}st

这条规则会把:

  • https://example.com/uk/test 重定向到 https://uk.example.com/test
  • https://example.com/images/toast 重定向到 https://images.example.com/toast

一条规则,覆盖无数变体。这就是通配符的价值。


没有通配符之前,用户有多痛苦

Cloudflare 在 2012 年推出的 Page Rules 原生支持通配符匹配。彼时,把旧路径重定向到新路径只需要两行配置:

复制代码
源 URL:  https://example.com/old-path/*
目标 URL:https://example.com/new-path/$1

2022 年,Cloudflare 推出了基于 Ruleset Engine 的 Single Redirects,作为 Page Rules URL 转发功能的现代替代品。新产品在性能和表达能力上更强,但当时不支持通配符。

要在 Single Redirects 里实现同样的"旧路径转新路径",写法变成了这样:

复制代码
过滤条件:
  (http.host eq "example.com" and
   starts_with(http.request.uri.path, "/old-path/"))

目标表达式:
  concat("/new-path/", substring(http.request.uri.path, 10))
  // 其中 10 是 /old-path/ 的字符长度,需要手动计算

对于有正则表达式基础的开发者来说,这个写法勉强可以接受。但对于绝大多数用户而言,starts_withsubstringconcat 嵌套起来,还要手动数字符串长度------这已经超出了"配置规则"的认知范畴,变成了"写代码"。

用户的反馈持续了两年,通配符支持是 Cloudflare Rules 产品收到最多的功能请求之一。


这次发布的三个新能力

1. 两个新的匹配操作符

在 Ruleset Engine 的过滤表达式里,新增了两个操作符:

wildcard (大小写不敏感):匹配时忽略大小写,testTesT 视为相同。行为和老版 Page Rules 一致,方便迁移。

strict wildcard (大小写敏感):严格匹配,test 不等于 TesT

这两个操作符可以作用于 Ruleset Engine 里所有的字符串字段,包括完整 URI、Host、HTTP 请求头、Cookie、User-Agent、来源国家等。

一个典型的 WAF 规则示例------匹配特定 User-Agent 格式的请求:

复制代码
http.user_agent wildcard "Mozilla/*(*Macintosh; Intel Mac OS*)*Gecko/*Firefox/*"

这条规则可以匹配所有符合该模式的 Firefox 请求,同时忽略大小写差异。

2. wildcard_replace() 函数

在 Single Redirects 里,新增了 wildcard_replace() 函数,允许在重定向目标 URL 里引用通配符匹配到的片段:

复制代码
wildcard_replace(
  http.request.full_uri,
  "https://example.com/*/page/*",
  "https://example.com/products/${1}?page=${2}"
)

这一条配置就能把所有符合模式的 URL 动态转换为新格式,不需要 concatsubstring,不需要数字符串长度。

3. 简化的可视化界面

对于不想写函数表达式的用户,Cloudflare 在 Single Redirects 的控制台界面里新增了"通配符模式"入口,直接填写源 URL 模式和目标 URL 模式,逻辑和 Page Rules 时代完全一致。从视觉上看和 Page Rules 几乎没有学习成本,背后运行的是更高性能的 Ruleset Engine。

覆盖的产品范围 :Cache Rules、Compression Rules、Configuration Rules、Custom Errors、Origin Rules、Redirect Rules、Snippets、Transform Rules、WAF、Waiting Room 以及其他基于 Ruleset Engine 的产品,全部适用。且对所有套餐用户免费开放。


工程实现:为什么要自己写一个通配符库

Ruleset Engine 核心用 Rust 实现。加入通配符支持时,团队首先评估了现有的 Rust crate。

为什么不用 regex crate

regex crate 是 Rust 生态里最成熟的正则表达式库。但问题在于,通配符模式需要先转换为正则表达式------* 转为 .*,同时还要对其他在正则里有特殊含义的字符做转义处理。这层转换增加了额外复杂度,而且引入了"通配符语义"和"正则语义"之间不必要的摩擦。

为什么不用 wildmatch crate

wildmatch 是专门为通配符匹配设计的 Rust 库,不需要转换为正则,也处理了通配符匹配的时间复杂度问题------在最坏情况下是 O(p + ℓ + s·ℓ),其中 p 是模式长度,ℓ 是输入串长度,s 是 * 号的数量。

wildmatch 有两个关键限制无法满足需求:

  • 只支持 UTF-8 字符串:Ruleset Engine 需要字节级别的匹配,不能假设输入是合法的 UTF-8
  • 不支持转义序列 :用户有时需要匹配字面量的 *,应该能用 \* 来表达,wildmatch 不支持这个

还有一个更根本的问题:wildcard_replace() 函数需要的不只是"是否匹配",而是"匹配到了什么"------需要把每个 * 对应的捕获片段提取出来,以便在目标 URL 里替换。wildmatch 没有这个能力。

自研的选择:Kurt 算法 + Krauss 优化

Cloudflare 最终决定自行实现一个 wildcard crate,基于 Kurt 2016 年的迭代算法,结合 Krauss 2014 年算法的优化改进。实现支持:

  • 字节级匹配:不限制输入必须是合法 UTF-8
  • 转义序列\* 表示字面量星号,\\ 表示字面量反斜杠
  • 捕获匹配段 :每个 * 匹配的子串都可以被提取,供 wildcard_replace() 使用

安全设计 :Ruleset Engine 将单个模式里的 * 数量上限设为 8 个。这个限制有两层意义:一是控制最坏情况下的时间复杂度,保证规则执行的性能下界;二是防止恶意用户通过构造极端复杂的模式和输入字符串来消耗过量 CPU,是一种主动的滥用防护设计。


总结

这次更新的表面是一个功能发布,背后是一次从用户体验出发的完整工程决策链:

用户反馈 → 找到根本问题(规则表达式对普通用户过于复杂)→ 评估现有方案(两个主流 crate 均不满足)→ 自研并开源(精确满足需求,同时回馈生态)→ 在多个产品和所有套餐上同步上线。

对于 Cloudflare 的用户,最直接的收益是:URL 重定向这件事,终于可以像十二年前用 Page Rules 一样简单直接地做到,同时享受新引擎的性能优势。

对于 Rust 开发者,wildcard crate 已经开源,字节级匹配、转义支持、捕获组提取,可以直接用于任何有类似需求的项目。

相关推荐
zhangfeng11333 小时前
宝塔服务器完全可以安装 Git,进行版本管理,而且非常简单
运维·服务器·人工智能·git·编程
芳草萋萋鹦鹉洲哦4 小时前
【tauri】为什么接口通信选择invoke而不是Axios
rust·axios·tauri·invoke
渔民小镇4 小时前
4 行代码接入 Spring —— ionet 的生态融合之道
java·服务器·分布式·游戏
海盗12344 小时前
C# OPC UA客户端开发实战
服务器·开发语言·c#
海域云-罗鹏5 小时前
豆包开启付费订阅,想白嫖越来越难了,企业不如部署自己的算力服务器
服务器·人工智能·github
德迅云安全-小潘5 小时前
APP运营服务器配置全攻略:从选型到网络安全,你需要知道的一切
运维·服务器·web安全
Yupureki6 小时前
《Linux网络编程》9.数据链路层原理
linux·运维·服务器·网络
dualven_in_csdn6 小时前
【assist】 需要用到的方法
linux·运维·服务器
minji...6 小时前
Linux 网络基础(二)HTTP协议,域名,URL,URI,认识HTTP的请求和响应
linux·服务器·网络·网络协议·http·tcp