220 lines
6.9 KiB
Markdown
220 lines
6.9 KiB
Markdown
```
|
|
接收API请求,提交内容管理任务(刷新/预热/分发)到配管系统。
|
|
|
|
【输入】ContentManageRequestParam
|
|
├─ contentURLs: List<UrlMd5> // URL列表(可能包含MD5)
|
|
├─ dirs: List<String> // 目录列表(目录刷新用)
|
|
├─ callBackUrl: String // 回调地址
|
|
└─ enterprise: String // 企业ID
|
|
|
|
【阶段1】verifyParam (行1094-1137)
|
|
↓ 校验URL数量、合法性、企业额度
|
|
↓ 从Redis批量获取域名缓存信息
|
|
└─ 输出: Tuple4<URL列表, URL→域名映射, 域名集合, 缓存域名信息>
|
|
|
|
【阶段2】checkValidDomainRefresh (行985-1078)
|
|
↓ 校验域名归属、状态、平面信息
|
|
↓ 精准域名(数据库) + 广义域名(泛域名匹配) + 冲突域名处理
|
|
↓ 缓存miss时查DB,写回Redis(TTL 1800秒)
|
|
└─ 输出: Map<域名, 平面JSON字符串>
|
|
|
|
【阶段3】buildContentTask (行856-930)
|
|
↓ 查询企业信息(cpId, 创建者, 省份)
|
|
↓ 构建BPM任务列表(每个URL一个task)
|
|
↓ 如果有回调URL,构建回调任务PO
|
|
└─ 输出: Tuple3<BPM请求, 回调任务PO, 回调URL列表PO>
|
|
|
|
【阶段4】sendContentTask (行787-848)
|
|
↓ 根据操作类型调用BPM接口:
|
|
│ INSERT → contentReload (预热)
|
|
│ DISTRIBUTE → contentDistribution (分发)
|
|
│ 其他 → contentRefresh (刷新)
|
|
↓ 成功后:
|
|
│ 1. 扣减企业额度
|
|
│ 2. 保存回调任务到DB (content_customize_task)
|
|
│ 3. 保存回调URL明细到DB (content_customize_url)
|
|
└─ 输出: taskId
|
|
|
|
---
|
|
三、核心数据表结构
|
|
|
|
1. content_customize_task (回调任务主表)
|
|
|
|
关键字段:
|
|
- id 主键
|
|
- cpId 企业cpId (纯数字)
|
|
- taskId 任务ID (UUID)
|
|
- callBackUrl 回调地址
|
|
- operationType 操作类型枚举
|
|
- state 任务状态 (0=待回调)
|
|
- callBack 回调状态 (0=未回调, 1=已回调)
|
|
- callBackSeparate 是否单独回调
|
|
|
|
用途: 记录需要异步回调的任务,供定时任务扫描并回调客户接口。
|
|
|
|
2. content_customize_url (回调URL明细表)
|
|
|
|
关键字段:
|
|
- id 主键
|
|
- taskId 任务ID (外键关联task表)
|
|
- url 具体URL
|
|
- operateType 操作类型 (0=预热,1=刷新,3=分发,4=目录刷新)
|
|
- urlIndex URL序号
|
|
- issuePlainInfo 平面信息JSON (List<Integer>)
|
|
- status URL执行状态
|
|
- nodeTotal 节点总数
|
|
- nodeSuccessCount 成功节点数
|
|
|
|
用途: 记录每个URL的执行详情,回调时提供细粒度状态。
|
|
|
|
---
|
|
四、校验规则详解
|
|
|
|
1. URL数量校验 (verifyParam)
|
|
|
|
普通操作(刷新/预热/分发): 单次最大 maxDir(配置,默认2000)
|
|
目录刷新: 单次最大 maxDirLength(配置,默认100)
|
|
|
|
2. URL合法性校验 (checkURL方法,未展示)
|
|
|
|
- URL格式验证
|
|
- 协议检查(http/https)
|
|
- 域名提取
|
|
|
|
3. 企业额度校验 (enterpriseContentNumberMaxNum)
|
|
|
|
每日默认额度:
|
|
- 普通操作: 2000次 (Constants.CONTENT_MAXOPERATION_DAY)
|
|
- 目录刷新: 100次 (Constants.CONTENT_MAXDIRS_DAY)
|
|
校验逻辑: 已用额度 + 本次请求数量 <= 企业配额
|
|
|
|
4. 域名归属校验 (checkValidDomainRefresh:1069-1072)
|
|
|
|
if (!enterpriseId.equals(domainInfo.getTenantId())) {
|
|
throw new PlatformException("域名:" + domain + "不存在");
|
|
}
|
|
关键: 防止企业操作其他企业的域名。
|
|
|
|
5. 域名状态校验 (checkValidDomainRefresh:1064-1067)
|
|
|
|
允许的域名状态:
|
|
- 已生效
|
|
- 部署中
|
|
- 部署失败
|
|
- 启用中
|
|
|
|
校验方法: DomainTicketStateEnum.judgeDomainState(domainInfo.getDomainState())
|
|
|
|
6. 域名类型处理
|
|
|
|
- 精准域名: 完全匹配 (http://www.example.com)
|
|
- 广义域名: 泛域名匹配 (*.example.com)
|
|
- 冲突域名: 多企业共用域名,通过cpDomain字段区分真实域名
|
|
|
|
---
|
|
五、关键业务逻辑
|
|
|
|
1. 域名缓存策略 (行1118-1133)
|
|
|
|
查询顺序:
|
|
Redis批量查询 → 缓存命中直接用
|
|
→ 缓存miss查DB → 写回Redis(TTL 30分钟)
|
|
|
|
广义域名永远查内存(不缓存到Redis的key)
|
|
|
|
问题: 广义域名每次都查全量,如果广义域名数量巨大会有性能问题。
|
|
|
|
2. 平面信息处理
|
|
|
|
平面 = CDN节点分组概念 (可能是地域/运营商等维度)
|
|
|
|
domainPlain.get(urlDomainMap.get(url)) // JSON字符串 "[1,2,3]"
|
|
↓ 解析
|
|
List<Integer> plains = JSONArray.parseArray(...) // [1,2,3]
|
|
|
|
每个URL会下发到对应的平面节点。
|
|
|
|
3. 操作类型路由 (handleContentTask:819-829)
|
|
|
|
switch (operationType) {
|
|
case INSERT: → bpm.contentReload() // 预热
|
|
case DISTRIBUTE: → bpm.contentDistribution() // 分发
|
|
default: → bpm.contentRefresh() // 刷新/其他
|
|
}
|
|
|
|
注意: DIRUPDATE(目录刷新)走的是default分支,即contentRefresh()。
|
|
|
|
---
|
|
六、异常处理机制
|
|
|
|
任何阶段失败 → 抛出PlatformException → 整个任务失败
|
|
→ 不会保存任何DB记录
|
|
→ 不会扣减企业额度
|
|
|
|
成功下发BPM后 → 立即扣减额度 + 保存回调任务
|
|
→ 如果回调任务保存失败?代码没处理这种情况!(bug风险)
|
|
|
|
---
|
|
七、代码问题清单
|
|
|
|
🔴 严重问题
|
|
|
|
4. Tuple滥用: Tuple4/Tuple3完全不可读,应该用命名类
|
|
5. 重复遍历:
|
|
- verifyParam遍历urlHostList构建urlHostMap
|
|
- buildContentTask又遍历contentUrlList
|
|
- 同样的数据被多次转换
|
|
6. 异常处理不完整:
|
|
|
|
// 行838-848
|
|
postSuccessActions(...) {
|
|
updateEnterpriseContentNumber(...); // 如果这里失败?
|
|
contentCustomizeTaskDao.save(...); // 如果这里失败?
|
|
contentCustomizeUrlDao.saveAll(...); // 如果这里失败?
|
|
}
|
|
这三个操作应该在一个事务里!
|
|
|
|
7. 缓存一致性风险:
|
|
- Redis缓存30分钟
|
|
- 如果DB中域名状态变更,缓存不会主动失效
|
|
- 可能导致已下线域名仍能操作
|
|
|
|
🟡 中等问题
|
|
|
|
8. 日志信息不足:
|
|
- 缺少域名校验失败的详细日志
|
|
- 缺少企业额度扣减的审计日志
|
|
9. 魔法数字:
|
|
- Redis TTL硬编码1800L
|
|
- 应该定义常量
|
|
10. 空指针风险:
|
|
// 行884
|
|
user = enterpriseInfo.getAccounts().get(0); // 如果accounts为空?
|
|
|
|
🟢 小问题
|
|
|
|
11. 变量命名混乱:
|
|
- urlPlain 实际是 domainPlainMap
|
|
- urlHost 实际是 validationResult
|
|
12. 注释质量差:
|
|
- "校验url数量、url合法性..." 这不是废话吗?
|
|
|
|
---
|
|
八、数据依赖关系
|
|
|
|
EnterpriseInfo (企业表)
|
|
└─ cpId, accounts, 额度信息
|
|
|
|
SelfServiceDomainConfig (域名配置表)
|
|
├─ domain (域名)
|
|
├─ cpDomain (冲突域名真实值)
|
|
├─ tenantId (所属企业)
|
|
├─ domainState (域名状态)
|
|
└─ domainPlain (平面信息JSON)
|
|
|
|
Redis缓存
|
|
key: content:domain:{domain}:{enterpriseId}
|
|
value: DomainEnterpriseInfoRedisPO
|
|
ttl: 1800秒
|
|
```
|