Initial commit

This commit is contained in:
Docker7530
2026-03-01 01:43:46 +08:00
commit c6125c117b
3840 changed files with 415340 additions and 0 deletions
@@ -0,0 +1,219 @@
```
接收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秒
```
@@ -0,0 +1,440 @@
```
1. 精准域名 - www.example.com 必须完全匹配
2. 冲突域名 - 多个企业可能配置同一个域名(联通/电信/移动各有一套)
3. 泛域名 - *.example.com 匹配所有子域名
"数据结构是什么?"
这才是关键:
【输入】
domains: [www.a.com, b.b.com, sub.c.com] // 用户请求的域名列表
absentDomain: [www.a.com, b.b.com] // Redis缓存未命中的域名
cacheDomain: {sub.c.com -> 域名信息PO} // Redis缓存命中的域名
【输出】
Map<域名, 平面JSON> = {
"www.a.com" -> "[1,2,3]", // 该域名可以下发到平面1,2,3
"b.b.com" -> "[1,2,5]",
"sub.c.com" -> "[1,2,3,4,5,6,7,8]"
}
---
【完整流程拆解】
阶段1: 初始化 (行993-998)
Map<String, DomainEnterpriseInfoRedisPO> preciseDomainMap = new HashMap<>();
if (!MapUtils.isEmpty(cacheDomain)) {
preciseDomainMap.putAll(cacheDomain); // 把Redis缓存的域名先放进来
}
目的: 构建一个"精准域名查找表",包含缓存+DB查询的完整域名信息。
---
阶段2: 处理未缓存的精准域名 (行1000-1035)
这是整段代码最复杂的部分,因为要处理冲突域名。
2.1 数据库查询
List<DomainEnterpriseInfoTmp> preciseDomains =
selfServiceDomainConfigDao.findDomainInfoByListDomain(absentDomain, enterpriseId);
SQL伪代码:
SELECT * FROM domain_config
WHERE domain IN ('www.a.com', 'b.b.com')
AND tenant_id = '企业123'
重要: 这里查询会返回两种情况的数据:
4. domain字段就是真实域名: {domain: 'www.a.com', cpDomain: null}
5. cpDomain字段是真实域名: {domain: 'www.a.com_conflict', cpDomain: 'www.a.com'}
---
2.2 构建两个Map (行1009-1014) - 关键设计
// Map1: 以domain字段为key
Map<String, Info> realDomainMap = {
"www.a.com" -> Info{domain='www.a.com', cpDomain=null, ...}
"b.b.com_conflict" -> Info{domain='b.b.com_conflict', cpDomain='b.b.com', ...}
}
// Map2: 以cpDomain字段为key (只包含冲突域名)
Map<String, Info> cpDomainMap = {
"b.b.com" -> Info{domain='b.b.com_conflict', cpDomain='b.b.com', ...}
}
为什么需要两个Map?
因为用户请求的是真实域名b.b.com,但数据库存储的可能是b.b.com_conflict!
---
2.3 遍历处理每个域名 (行1017-1034) - 双重匹配逻辑
for (String domain : absentDomain) { // domain = "b.b.com"
DomainEnterpriseInfoRedisPO redisPO = null;
// 第一次尝试: 直接匹配domain字段
DomainEnterpriseInfoTmp tmpInfo = realDomainMap.get(domain);
if (tmpInfo != null) {
redisPO = convert(tmpInfo);
} else {
// 第二次尝试: 从冲突域名Map中匹配cpDomain字段
tmpInfo = cpDomainMap.get(domain); // 用b.b.com查cpDomain
if (tmpInfo != null) {
redisPO = convert(tmpInfo);
redisPO.setDomain(domain); // 🔴 关键:覆盖domain为真实域名
}
}
if (redisPO != null) {
preciseDomainMap.put(domain, redisPO);
redis.set(cacheKey, redisPO, 1800秒); // 写回缓存
}
}
举例说明冲突域名处理:
数据库记录:
┌─────────────────────┬──────────────┬────────────┐
│ domain │ cpDomain │ tenantId │
├─────────────────────┼──────────────┼────────────┤
│ www.a.com │ NULL │ 企业123 │ // 普通域名
│ b.b.com_unicom │ b.b.com │ 企业123 │ // 冲突域名(联通)
│ b.b.com_telecom │ b.b.com │ 企业456 │ // 冲突域名(电信)
└─────────────────────┴──────────────┴────────────┘
用户请求: ["www.a.com", "b.b.com"]
处理流程:
6. www.a.com → realDomainMap.get("www.a.com") ✅ 直接命中
7. b.b.com → realDomainMap.get("b.b.com") ❌ 未命中
→ cpDomainMap.get("b.b.com") ✅ 命中 b.b.com_unicom
→ 覆盖domain字段为 "b.b.com"
→ Redis缓存key用真实域名 "b.b.com"
设计意图:
- 数据库用domain_conflict存储避免主键冲突
- 但对用户透明,用户永远使用真实域名
- 通过企业ID区分不同企业的同名域名
---
阶段3: 处理广义域名(泛域名) (行1037-1061)
Map<String, DomainEnterpriseInfoRedisPO> extensiveDomainMap = new HashMap<>();
for (String domain : domains) { // 遍历所有域名
DomainEnterpriseInfoRedisPO domainInfo = preciseDomainMap.get(domain);
if (domainInfo == null) { // 精准域名没找到
// 延迟加载:只在第一次需要时才查询广义域名
if (extensiveDomainMap.isEmpty()) {
List<Info> extensiveDomains = service.findAllExtensiveDomain();
extensiveDomainMap = toMap(extensiveDomains);
// 可能包含: {"*.example.com", "*.test.com"}
}
// 泛域名匹配
String matchedDomain = matchExtensiveDomain(domain, extensiveDomainMap.keySet());
// 例: domain="sub.example.com" → 匹配到 "*.example.com"
if (StringUtils.isBlank(matchedDomain)) {
throw new PlatformException("未查询到域名 " + domain);
}
domainInfo = extensiveDomainMap.get(matchedDomain); // 使用泛域名的配置
redis.set(cacheKey, domainInfo, 1800秒); // 也缓存到Redis
}
// ... 后续校验
}
泛域名匹配算法 (CdniContextVO.matchExtensiveDomain)
public static String matchExtensiveDomain(String domain, Collection<String> extensiveDomains) {
// domain = "sub.example.com"
// extensiveDomains = ["*.example.com", "*.test.com"]
int index = domain.indexOf('.'); // index = 3
if (index != -1) {
String match = "*" + domain.substring(index); // match = "*.example.com"
for (String s : extensiveDomains) {
if (match.equals(s)) {
return s; // 返回 "*.example.com"
}
}
}
return null;
}
匹配逻辑:
sub.example.com → *.example.com ✅
a.b.example.com → *.b.example.com (如果存在) ✅
→ 否则匹配失败 ❌
注意: 只匹配第一级子域名!
延迟加载优化:
if (extensiveDomainMap.isEmpty()) {
// 只在第一次遇到泛域名需求时才查询
// 如果所有域名都是精准域名,这个查询就省了
}
---
阶段4: 校验域名状态和企业归属 (行1063-1074)
// 4.1 状态校验
if (!DomainTicketStateEnum.judgeDomainState(domainInfo.getDomainState())) {
throw new PlatformException("域名状态无效");
}
// 允许的状态: 已生效、部署中、部署失败、启用中
// 4.2 企业归属校验
if (!enterpriseId.equals(domainInfo.getTenantId())) {
throw new PlatformException("域名不存在"); // 实际是权限不足
}
// 4.3 提取平面信息
result.put(domain, domainInfo.getDomainPlain());
// domainPlain 是JSON字符串: "[1,2,3,4,5]"
---
【完整数据流示例】
假设场景:
用户请求:
domains = ["www.a.com", "sub.b.com", "c.example.com"]
enterpriseId = "企业123"
Redis缓存:
命中: {"www.a.com" -> Info{...}}
未命中: ["sub.b.com", "c.example.com"]
数据库 domain_config:
┌──────────────────┬────────────┬──────────────┬──────────────┐
│ domain │ cpDomain │ tenantId │ domainPlain │
├──────────────────┼────────────┼──────────────┼──────────────┤
│ www.a.com │ NULL │ 企业123 │ [1,2,3] │
│ sub.b.com │ NULL │ 企业123 │ [1,2,5] │
│ *.example.com │ NULL │ 企业123 │ [1,2,3,4,5] │
└──────────────────┴────────────┴──────────────┴──────────────┘
执行流程:
┌─ 阶段1: 初始化 ─────────────────────────────────┐
│ preciseDomainMap = {"www.a.com" -> Info{...}} │ // 来自Redis
└──────────────────────────────────────────────┘
┌─ 阶段2: 查询DB ──────────────────────────────────┐
│ absentDomain = ["sub.b.com", "c.example.com"] │
│ ↓ DB查询 (精准域名) │
│ 结果: [Info{domain='sub.b.com', ...}] │
│ c.example.com 未找到 │
│ ↓ 处理 │
│ preciseDomainMap.put("sub.b.com", ...) │
│ Redis.set("sub.b.com", ..., 1800秒) │
└──────────────────────────────────────────────┘
┌─ 阶段3: 泛域名匹配 ────────────────────────────────┐
│ 遍历: ["www.a.com", "sub.b.com", "c.example.com"]│
│ │
│ www.a.com → preciseDomainMap.get() ✅ │
│ sub.b.com → preciseDomainMap.get() ✅ │
│ c.example.com → preciseDomainMap.get() ❌ │
│ ↓ 触发广义域名查询 │
│ extensiveDomainMap = {"*.example.com"│-> Info}
│ ↓ 匹配 │
│ matchExtensiveDomain("c.example.com")│
│ → "*.example.com" ✅ │
│ ↓ 使用泛域名配置 │
│ domainInfo = Info{domain='*.example.com', plain='[1,2,3,4,5]'}
└──────────────────────────────────────────────┘
┌─ 阶段4: 校验 + 输出 ─────────────────────────────┐
│ result = { │
│ "www.a.com" -> "[1,2,3]", │
│ "sub.b.com" -> "[1,2,5]", │
│ "c.example.com" -> "[1,2,3,4,5]" // 泛域名的平面│
│ } │
└──────────────────────────────────────────────┘
---
【代码问题分析】
🔴 严重问题
1. 冲突域名处理的设计缺陷
// 行1026
redisPO.setDomain(domain); // 直接修改对象
这个操作污染了数据!如果tmpInfo被其他地方引用,也会被修改。应该:
redisPO = tmpInfo.cloneAndSetDomain(domain); // 创建新对象
2. 广义域名查询性能问题
// 行1045
List<Info> extensiveDomains = service.findAllExtensiveDomain();
// 查询全量泛域名!如果有1000个泛域名,全部加载到内存
问题:
- 每次处理任务时,只要有一个域名需要泛域名匹配,就查询全部
- 没有缓存到Redis(只缓存匹配结果)
- 如果泛域名数量巨大,这是性能炸弹
改进:
// 泛域名应该缓存到Redis或本地内存
private static final Cache<String, List<Info>> EXTENSIVE_DOMAIN_CACHE =
CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
3. 缓存一致性问题
// 行1032、1060
redisUtil.setJSONString(key, redisPO, 1800L); // 30分钟
问题场景:
4. 域名状态从"已生效"变更为"已下线"
5. Redis缓存还有30分钟才过期
6. 用户仍然可以操作已下线的域名!
解决方案:
- 域名状态变更时主动清除Redis缓存(事件总线)
- 或者缩短TTL到5分钟
4. 重复查询问题
// 行1002
List<Info> preciseDomains = dao.findDomainInfoByListDomain(absentDomain, enterpriseId);
// 如果absentDomain = ["a.com", "b.com", "c.com"]
// 而数据库只有 a.com 和 b.com
// c.com 不存在,直接抛异常 (行1005)
问题: 无法区分"域名不存在"还是"需要泛域名匹配"。
正确流程:
5. 查询精准域名,允许部分未找到
6. 未找到的再尝试泛域名匹配
7. 最后仍未找到才抛异常
但当前代码:
- 如果查询结果为空,直接抛异常
- 导致泛域名逻辑(行1037)永远无法执行!
等等,我看错了吗?让我重新看代码...
// 行1002
List<Info> preciseDomains = dao.findDomainInfoByListDomain(absentDomain, enterpriseId);
if (CollectionUtils.isEmpty(preciseDomains)) {
log.error("域名不存在: {}", absentDomain);
throw new PlatformException("未查询到域名信息"); // 🔴 这里直接抛异常了!
}
妈的,这是个BUG!
如果absentDomain中全是泛域名的子域名(比如sub.example.com),数据库查不到精准记录,会直接抛异常,永远走不到泛域名匹配逻辑(行1037)!
正确逻辑应该是:
if (!CollectionUtils.isEmpty(absentDomain)) {
List<Info> preciseDomains = dao.findDomainInfoByListDomain(absentDomain, enterpriseId);
// 允许查询结果为空,部分域名可能是泛域名
if (!CollectionUtils.isEmpty(preciseDomains)) {
// 处理查到的精准域名
// ...
}
// 未查到的域名留给后面的泛域名匹配
}
---
🟡 中等问题
5. 方法命名误导
private Map<String, String> checkValidDomainRefresh(...)
方法名叫checkValidDomainRefresh,但实际上:
- 不仅校验,还查询、转换、缓存
- 不仅适用于Refresh,INSERT/DISTRIBUTE也用这个方法
应该叫:
private Map<String, String> resolveDomainPlainsWithValidation(...)
6. 日志不足
缺少关键日志:
- 冲突域名处理的日志
- 泛域名匹配的日志
- Redis缓存命中率日志
---
【Linus式总结】
核心判断
这段代码在解决真实问题吗? → ✅ 是的
- CDN系统确实需要支持精准域名+泛域名+多租户隔离
- 缓存策略也是必要的(减少DB压力)
数据结构设计合理吗? → ⚠️ 凑合
- 用两个Map处理冲突域名,思路正确但实现有bug
- 延迟加载广义域名是好的优化
有特殊情况需要消除吗? → 🔴 有!
- 冲突域名的特殊处理应该封装成独立方法
- 精准域名和泛域名的处理应该统一
---
改进方案
如果让我重写这段代码:
private Map<String, String> resolveDomainPlains(
Set<String> domains,
String enterpriseId,
Map<String, DomainInfo> cached) {
DomainResolver resolver = DomainResolver.builder()
.withCache(cached)
.withEnterpriseId(enterpriseId)
.build();
Map<String, String> result = new HashMap<>();
for (String domain : domains) {
DomainInfo info = resolver.resolve(domain);
// 内部统一处理: 缓存查询 → 精准域名 → 冲突域名 → 泛域名
info.validateState();
info.validateOwnership(enterpriseId);
result.put(domain, info.getPlains());
}
return result;
}
消除特殊情况,用统一的Resolver模式。
---
最终评价
品味评分: 🟡 凑合
问题:
1. 有个严重BUG(行1003-1005的异常处理)
2. 缓存一致性风险
3. 泛域名查询性能隐患
优点:
4. 延迟加载广义域名是个好主意
5. 冲突域名处理思路正确
"这代码能用,但有定时炸弹。那个精准域名查询为空就抛异常的逻辑,需要立即修复。"
---
现在清楚这段域名校验逻辑了吗?有哪里不明白的?
```
@@ -0,0 +1,107 @@
# 2.1 跨客户订购迁移流程自动化(涉及子系统与CPID字段解耦)
## 需求评审
NRWLXT-30203
**功能说明:** 针对不同 cpid 的冲突域名,预热刷新及 URL 封禁, 我们把 A 转为 A^,底层回调给我们的也按照 A^回调,展示给客户的结果按照 A 展示。
**需求来源:** 集团-高旭、韩齐雅
**需求背景:**
政企侧 2025 年订购迁移需求呈现出密集、不定期态势,主要为从【总部政企】迁移至【省公司政企】需求。
政企侧要求订购迁移时,保障业务服务不中断、计费数据不受影响(一般需要某月 1 号 00:00 分新订购生效计费,前一日 23:59 分旧订购中止)。
由于订购迁移主要为【订购ID】和【CPID】变更,当前各系统和平面与 CPID 字段耦合严重,导致订购迁移工作组织消耗大量人力。
当前不同场景订购迁移各系统需配合的工作,主要涉及:IBS、CRS、集中配管、自研平面、中兴平面、华为平面,以及客户侧配合变更 AKSK 等。
**具体描述:**
1、预热刷新:针对冲突域名,不同 CPID 时,客户下发预热刷新任务时(接口、页面),需将URL中的原始域名修改为加后缀的冲突域名给下游系统。查询任务时,将待后缀的冲突域名转换回原始域名给客户展示。
2、[CDN运营平台接口规范-客户版-20250519](https://www.kdocs.cn/office/w/cnS6vYEirmwO?sub_file_id=AEITSOBCADQHU&attachment_store_type=upload_ks3&disablePlugins&readonly) 涉及 4 内容管理接口、8.1 解封禁接口、8.2 URL 封禁/解封任务查询接口。
3、相同 cpid 下的不做任何逻辑处理,子账号做同步处理。
4、场景说明
1A:冲突a  展示原始a
(2)A:冲突a+冲突2a   展示冲突a+冲突2a
(3)A:冲突a+冲突b  展示原始a +原始b
(4)A:原始a+冲突b   展示原始a +原始b
(5)A:原始a+冲突a    展示原始a+冲突a
## 需求备注
老接口:com.cmcc.cdn.api.service.impl.ContentApiServiceImpl#submitContentTasksFromApi
正哥写的新接口:
com.cmcc.cdn.api.service.impl.ContentApiServiceImpl#submitContentTasksFromApiNew
## 需求开发
```
/**
* 根据企业ID集合查询活跃域名信息
* 返回包含企业ID和域名的投影对象列表
*/
@Query("select s.tenantId as tenantId, s.domain as domain from SelfServiceDomainConfigPO s "
+ "where s.tenantId in :tenantIds and s.deleted = false and s.state in :states")
List<TenantDomainProjection> findActiveDomainsByTenantIds(@Param("tenantIds") Collection<String> tenantIds,
@Param("states") Collection<DomainTicketStateEnum> states);
```
1、 客户同时拥有冲突域名和真实域名,当在缓存失效内,删除了真实域名,这时候处理冲突域名的时候会存在获取异常。
2、 4.5 支持域名和 URL 维度查询。历史没有校验直接给配管。现在因为要做冲突域名转换。如果没有查到域名信息和 rul 中的 hsot 信息,我们要进行异常抛出吗?
URL 解封禁途径:
```
deny_allow_task 库表存储
更新(网宿URL封禁/解禁回调入口):/v1/url/ban/callback
新增(URL封禁/解禁,网速封禁):/api/normal/url/ban
新增
/action?commandType=urlbanorunban
/api/toutiao/url/ban
/api/url/ban8.1
更新:/actionpm?commandType=pipeDomainCallBack
/v1/pipe/config/callback
```
# 用例评审
# 冒烟自测
## API 接口
**URL预热**
```
https://apppkg-p02-bg-drcn.hihonorcdn.com/diff/com.zhongyuedu.zhongyuzhongyi_183_19_186_0_e6f007_3d1930_1761718044875.diff
```
**内容刷新**
```
https://contentplatform-drcn.hihonorcdn.com.wskam.com/AdPlatformDelivery/landingPagePkgName/com.jzxy.heisu.json
```
**目录刷新**
```
https://s-file-1.ykt.cbern.com.cn/
```