From 7401f5d0b4bc49d922bb29418e940df71b6fe86a Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 18 Jul 2026 23:24:23 +0800 Subject: [PATCH] =?UTF-8?q?docs(design):=20=E8=BE=B9=E7=BC=98=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E9=BB=98=E8=AE=A4=E5=8F=AF=E7=BC=93=E5=AD=98=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E5=AF=B9=E6=A0=87=20Cloudflare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 约定开启缓存默认 static 扩展名策略,存量 url 映射为 all, 并明确第一期不做 Edge TTL/Purge/Cache Rules。 --- docs/config.ts | 1 + docs/design/architecture.md | 2 +- docs/design/edge-cache-design.md | 189 +++++++++++++++++++++++++++++++ docs/design/index.md | 1 + 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 docs/design/edge-cache-design.md diff --git a/docs/config.ts b/docs/config.ts index be7880ed..1d6887b7 100644 --- a/docs/config.ts +++ b/docs/config.ts @@ -132,6 +132,7 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] { { text: 'WAF 设计', link: 'waf-design' }, { text: 'WAF 可编排规则设计', link: 'waf-orchestration-design' }, { text: 'Pages 静态托管设计', link: 'pages-design' }, + { text: '边缘缓存策略设计', link: 'edge-cache-design' }, { text: '边缘可观测与业务流量统计', link: 'observability-design' }, { text: '观测数据传输模型', link: 'observability-transport-model' }, { text: '观测上报协议与表结构', link: 'observability-data-model' }, diff --git a/docs/design/architecture.md b/docs/design/architecture.md index 477a21f5..0f63aa51 100644 --- a/docs/design/architecture.md +++ b/docs/design/architecture.md @@ -95,7 +95,7 @@ OpenResty (Agent, TLS/WAF) ### 3. OpenResty (数据面) 接收访客流量并执行最终的业务落地: * 流量入口,支持 HTTP/2、HTTP/3(QUIC)和 TLS 证书动态绑定。 -* 嵌入 Lua 逻辑,在 `access_by_lua` 阶段高效过滤 WAF 规则、验证工作量证明 (PoW) 挑战,并在此之后执行连接数/速率限制及基础缓存。 +* 嵌入 Lua 逻辑,在 `access_by_lua` 阶段高效过滤 WAF 规则、验证工作量证明 (PoW) 挑战,并在此之后执行连接数/速率限制及基础缓存(策略见 [边缘缓存策略设计](./edge-cache-design.md))。 * *详细设计请参阅:[WAF 设计文档](./waf-design.md) 与 [Pages 静态托管设计文档](./pages-design.md)* ### 4. Relay 与 OpenFlared (穿透组件) diff --git a/docs/design/edge-cache-design.md b/docs/design/edge-cache-design.md new file mode 100644 index 00000000..ed06f1a5 --- /dev/null +++ b/docs/design/edge-cache-design.md @@ -0,0 +1,189 @@ +# 边缘缓存策略设计(对标 Cloudflare 默认可缓存范围) + +你会学到:OpenFlare 边缘 `proxy_cache` 的产品边界、默认可缓存范围如何对齐 Cloudflare「静态资源默认可缓存」、策略枚举与渲染规则、兼容迁移,以及本阶段明确不做的能力。 + +本设计是 [系统架构](./architecture.md) 中「基础缓存」的产品化专章;访问日志中的缓存结果见 [观测数据模型 §3.5.1](./observability-data-model.md)。 + +--- + +## 1. 目标与非目标 + +### 1.1 目标(第一期) + +* **开箱接近 CF 默认**:路由开启缓存后,**默认只缓存静态扩展名**,不默认缓存 HTML/无扩展名动态路径。 +* **行为可解释**:与现有安全旁路(非 GET、Authorization、会话 Cookie、请求 `Cache-Control`)叠加,不削弱安全。 +* **可观测一致**:继续依赖 `$upstream_cache_status` → `cache_status` 明细三态。 +* **兼容存量**:旧路由 `cache_policy=url`(近似「过旁路即可缓存」)迁移为显式策略 `all`,行为不变。 + +### 1.2 非目标(后续迭代) + +* Cache Rules 表达式引擎 +* Edge TTL / `proxy_cache_valid` / 忽略源站 `Cache-Control` +* 可配置 Cookie 旁路列表、Query 忽略列表 +* Purge(按 URL/前缀/全站) +* 浏览器 TTL 改写、客户端 `CF-Cache-Status` 响应头 +* 命中率看板 + +--- + +## 2. 现状摘要 + +| 层 | 现状 | +| --- | --- | +| 全局 | `proxy_cache_path` / key / lock / stale(Performance 部分字段) | +| 路由 | `cache_enabled` + `cache_policy`:`url` \| `suffix` \| `path_prefix` \| `path_exact` | +| 旁路 | 渲染器硬编码:非 GET、Authorization、会话 Cookie、请求 Cache-Control | +| TTL | **无** `proxy_cache_valid`;存多久主要看源站头 + `inactive` | +| 观测 | 已上报 `cache_status`,UI 三态:命中 / 回源 / 未缓存 | + +问题:默认策略 `url` 对「过旁路的 GET」范围过宽,与 CF「默认主要缓存静态扩展名、默认不缓存 HTML」不一致。 + +--- + +## 3. 产品语义 + +### 3.1 双层开关(不变) + +* **全局** `openresty_cache_enabled`:生成 `proxy_cache_path` 等;关闭则路由级缓存指令不生效。 +* **路由** `cache_enabled`:是否在该站点 `location` 启用 `proxy_cache`。 + +两者均开启时才进入缓存逻辑。 + +### 3.2 策略枚举(第一期) + +| `cache_policy` | 含义 | 新建默认 | 旧值兼容 | +| --- | --- | --- | --- | +| **`static`** | 仅 URI 匹配**标准静态扩展名**(内置表)才允许缓存 | **是** | — | +| **`all`** | 过安全旁路后,不限制路径/扩展名(等同今日 `url`) | 否 | 存量 `url` → `all` | +| **`suffix`** | 自定义扩展名列表(`cache_rules`) | 否 | 保持 | +| **`path_prefix`** | 自定义路径前缀 | 否 | 保持 | +| **`path_exact`** | 自定义精确路径 | 否 | 保持 | + +> 渲染层:读到历史值 `url` 时按 `all` 处理,避免未迁移数据行为突变;API 校验与 UI 只暴露上表枚举(写入时可将 `url` 规范为 `all`)。 + +### 3.3 标准静态扩展名(内置,V1 硬编码) + +对齐 Cloudflare 常见「默认可缓存静态」集合,**默认不包含** `html` / `htm`: + +```text +css js mjs map json +ico cur gif jpg jpeg png webp avif svg svgz +ttf otf woff woff2 eot +mp3 mp4 webm ogg flac +wasm pdf +zip 7z gz tar +``` + +* 匹配对象:`$uri` 的扩展名(大小写不敏感),实现上与现有 `suffix` 策略相同: + `if ($uri !~* \.(?:css|js|…)$) { set $openflare_skip_cache 1; }` +* **V1.1(可选)**:全局配置项覆盖该列表;第一期不强制。 + +### 3.4 安全旁路(保持硬编码) + +在策略匹配之前/之外,仍设置 `$openflare_skip_cache=1`: + +1. `$request_method != GET`(含 HEAD,与现网一致) +2. `$http_authorization != ""` +3. 会话类 Cookie 正则(现网列表) +4. 请求 `$http_cache_control` 匹配 `no-cache|no-store|private` + +`proxy_cache_bypass` / `proxy_no_cache` 均绑定 `$openflare_skip_cache`。 + +### 3.5 与源站头的关系(本阶段不改) + +* 仍不输出 `proxy_cache_valid`。 +* 对象**是否进入缓存流程**由策略 + 旁路决定;**存多久**继续依赖源站 `Cache-Control` / `Expires` 等及全局 `inactive`。 +* Edge TTL / 强制忽略源站头 → 后续专项。 + +--- + +## 4. 渲染与数据流 + +```text +全局 cache_enabled? + │ no → 不生成 proxy_cache_* + ▼ yes +路由 cache_enabled? + │ no → location 无 proxy_cache + ▼ yes +set $openflare_skip_cache 0 + → 安全旁路 if → 置 1 + → 策略 if(static/all/suffix/…)→ 可置 1 +proxy_cache openflare_cache +proxy_cache_methods GET +proxy_cache_bypass / proxy_no_cache $openflare_skip_cache + → +access.log cache_status=$upstream_cache_status +``` + +### 4.1 策略 → Nginx 条件 + +| 策略 | 额外条件 | +| --- | --- | +| `static` | `$uri` 不匹配内置扩展名表 → skip | +| `all` | 无额外路径条件 | +| `suffix` | 不匹配 `cache_rules` 扩展名 → skip | +| `path_prefix` / `path_exact` | 同现实现 | + +### 4.2 涉及代码面(实现时) + +| 区域 | 路径 | +| --- | --- | +| 渲染 | `pkg/render/openresty/render.go`(策略分支 + 内置扩展名常量) | +| 校验 | `internal/apps/openflare/proxy_route/helpers.go` | +| 模型/默认 | 创建路由默认 `cache_policy=static`;读写时 `url`→`all` | +| 快照 | `config_version/snapshot.go` | +| UI | `proxy-routes/detail/components/cache-section.tsx` | +| 测试 | `pkg/render/openresty/render_test.go`、proxy_route helpers 测试 | + +--- + +## 5. 兼容与迁移 + +| 数据 | 处理 | +| --- | --- | +| DB 中 `cache_policy=''` 或 `url` | 读取/发布时规范为 `all`;可选一次性 SQL 更新为 `all` | +| 新建路由 | 默认 `cache_enabled=false`;若用户开启缓存,表单默认策略 **`static`** | +| 已开启且 `url` 的站点 | 迁移后为 `all`,**缓存范围不变** | +| 期望「只缓存静态」的旧站点 | 用户在 UI 改为 `static` 或自定义 `suffix` | + +**发布说明建议:** 说明默认策略变更仅影响**新配置**;存量 `url` 视为 `all`。 + +--- + +## 6. UI 文案要点(缓存 Tab) + +* 开启缓存后默认:**标准静态资源**(列出扩展名摘要,并写明不含 HTML)。 +* 选项:**标准静态资源** / **所有可缓存 GET(高级)** / 自定义后缀 / 路径前缀 / 精确路径。 +* 固定说明:非 GET、带 Authorization、常见登录 Cookie、请求禁止缓存头时跳过缓存。 +* 提示:全局 Performance 中缓存总开关须开启,否则站点开关无效。 + +--- + +## 7. 验证要点 + +* 渲染:`static` 生成扩展名 `if`;`all`/`url` 无路径限制;旁路四条仍在。 +* 单测:内置表含 `css`/`js`/`woff2`,不含 `html`。 +* 手动:开启 `static` 后请求 `/a.css` 可出现 HIT/MISS;`/index.html` 或 `/api` 多为未缓存/BYPASS。 +* 观测:access log `cache_status` 与列表三态一致。 + +--- + +## 8. 后续路线图(非本设计交付) + +1. **Edge TTL / 尊重源站开关**(`proxy_cache_valid`、`proxy_ignore_headers`) +2. **可配置旁路**(Cookie/Query) +3. **Purge API** +4. **Cache Rules**(有序规则 + 动作) +5. **全局默认可缓存扩展名配置** + +--- + +## 9. 决策记录 + +| 决策 | 选择 | 原因 | +| --- | --- | --- | +| 默认可缓存范围 | 开启缓存默认 `static` 扩展名表 | 对标 CF 开箱行为,降低 HTML/API 被误缓存 | +| 旧 `url` | 映射为 `all` | 避免存量站点行为变化 | +| HTML | 默认不在白名单 | 对齐 CF 默认不缓存 HTML | +| 第一期不做 Edge TTL/Purge | 明确 Out of Scope | 先收敛「谁可以进缓存」再优化「存多久/怎么清」 | diff --git a/docs/design/index.md b/docs/design/index.md index 7d4d4bc6..b2fb386d 100644 --- a/docs/design/index.md +++ b/docs/design/index.md @@ -22,6 +22,7 @@ OpenFlare 适合需要统一管理多台 OpenResty 代理节点的团队,具 | 能力 | 说明 | 详细设计/使用指南 | | --- | --- | --- | | **反代配置管理** | 以网站规则(Proxy Route)为聚合边界,支持多域名与多上游负载均衡 | [新建反代配置](../guide/proxy-config.md) | +| **边缘缓存** | 单节点 OpenResty `proxy_cache`;开启后默认仅缓存标准静态扩展名(对标 CF 默认可缓存范围) | [边缘缓存策略设计](./edge-cache-design.md) | | **Zone 与域名管理** | 以可注册根域为管理入口,聚合明确域名、域名证书与反代路由 | [Zone 与域名资源设计](./zone-design.md) | | **配置版本控制** | 支持全局单一激活版本的预览、发布、不可变快照历史与秒级一键回滚 | [Agent 与发布模型](./agent-design.md) | | **WAF 安全防护** | 支持可视化 DAG 编排规则、手动/自动/订阅型 IP 组、GeoIP 匹配与 PoW CC 防护 | [WAF 设计](./waf-design.md) / [WAF 可编排规则设计](./waf-orchestration-design.md) / [WAF 使用指南](../guide/waf-usage.md) |