6.9 KiB
6.9 KiB
接收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秒