位置:lib/services/device/device_auth_service.dart:167-168
Future<DeviceQuotaInfo?> fetchQuota() async {
if (!kHasBundledBackend) return null;
final token = _cachedToken;
if (token == null) return null; // ← 只判 null,未判空串
return fetchMeWithToken(token);
}
问题:token 守卫只过滤 null,没过滤空串。loadCached()(line 80-82)走 PreferencesService.instance.getString(_kDeviceToken),而该方法在 key 缺失时默认返回 ''(见 preferences_service.dart:46-54)。新装/未注册设备首次启动后 _cachedToken 为 '' 而非 null,守卫被绕过,fetchMeWithToken('') 会用 Authorization: Bearer (空)请求 /api/v1/devices/me,后端必 401。
影响:
- 每次新装用户首次进入「AI 配置」页都会发起一个注定 401 的请求,浪费一次 RTT、污染后端日志。
fetchMeWithToken 收到 401 后会打 LoggerService warning 日志(device/quota 标签),增加无意义告警量。
- 测试
device_auth_quota_test.dart:155-173 的「无缓存 token 守卫」用例因 kHasBundledBackend 是编译期常量(build_config.dart:20)而被死代码化——守卫逻辑实际从未在测试中真正执行过,未来翻车也没回归兜底。
修复建议:
final token = _cachedToken;
if (token == null || token.isEmpty) return null;
顺手把 _cachedToken 的空串状态在 loadCached 里就归一化为 null(与字段默认一致),避免后续 ensureRegistered 等其它路径也踩同样的坑(仓库中 ensureRegistered 的 if (cached != null) return cached; 同样会返回空串,性质一致;本次仅修 fetchQuota,剩余路径可另开 issue)。
忽略指南:在 lib/services/device/device_auth_service.dart:168 添加注释 // cr-ignore <CR_IGNORE_IID_HASH>: <你的理由>,下次审查会自动关闭。
位置:
lib/services/device/device_auth_service.dart:167-168问题:
token守卫只过滤null,没过滤空串。loadCached()(line 80-82)走PreferencesService.instance.getString(_kDeviceToken),而该方法在 key 缺失时默认返回''(见preferences_service.dart:46-54)。新装/未注册设备首次启动后_cachedToken为''而非null,守卫被绕过,fetchMeWithToken('')会用Authorization: Bearer(空)请求/api/v1/devices/me,后端必 401。影响:
fetchMeWithToken收到 401 后会打LoggerServicewarning 日志(device/quota标签),增加无意义告警量。device_auth_quota_test.dart:155-173的「无缓存 token 守卫」用例因kHasBundledBackend是编译期常量(build_config.dart:20)而被死代码化——守卫逻辑实际从未在测试中真正执行过,未来翻车也没回归兜底。修复建议:
顺手把
_cachedToken的空串状态在loadCached里就归一化为 null(与字段默认一致),避免后续ensureRegistered等其它路径也踩同样的坑(仓库中ensureRegistered的if (cached != null) return cached;同样会返回空串,性质一致;本次仅修 fetchQuota,剩余路径可另开 issue)。忽略指南:在
lib/services/device/device_auth_service.dart:168添加注释// cr-ignore <CR_IGNORE_IID_HASH>: <你的理由>,下次审查会自动关闭。