优化配置,修复 demo bug
1,network 框架完善 2,websocket 机制完善 3,设计文档整理到架构文档 4,脚本,配置完善
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/// API 错误码常量
|
||||
///
|
||||
/// 集中管理后端业务错误码,避免散落在各处硬编码。
|
||||
/// 按业务域分组,命名风格对齐后端定义。
|
||||
///
|
||||
/// 使用方式:
|
||||
/// ```dart
|
||||
/// ApiConfig(
|
||||
/// tokenExpiredCodes: ApiErrorCodes.tokenExpiredCodes,
|
||||
/// forceLogoutCodes: ApiErrorCodes.forceLogoutCodes,
|
||||
/// )
|
||||
/// ```
|
||||
class ApiErrorCodes {
|
||||
ApiErrorCodes._();
|
||||
|
||||
// ── 认证(30001-30009)──
|
||||
|
||||
/// Token 无效
|
||||
static const int tokenInvalid = 30002;
|
||||
|
||||
/// JWT 无效
|
||||
static const int jwtInvalid = 30003;
|
||||
|
||||
/// 签名方法错误
|
||||
static const int signingMethodError = 30008;
|
||||
|
||||
/// 密钥解析失败
|
||||
static const int parsingKeyError = 30009;
|
||||
|
||||
/// Session 无效
|
||||
static const int sessionInvalid = 30124;
|
||||
|
||||
/// Refresh Token 失效
|
||||
static const int refreshTokenFailed = 30125;
|
||||
|
||||
/// 账号在其他设备登录
|
||||
static const int loggedInAnotherDevice = 30006;
|
||||
|
||||
// ── 错误码集合 ──
|
||||
|
||||
/// Token 过期错误码集合 — 触发自动刷新 Token
|
||||
static const Set<int> tokenExpiredCodes = {
|
||||
tokenInvalid,
|
||||
jwtInvalid,
|
||||
sessionInvalid,
|
||||
};
|
||||
|
||||
/// 强制登出错误码集合 — 触发退出登录流程
|
||||
static const Set<int> forceLogoutCodes = {refreshTokenFailed};
|
||||
|
||||
/// 踢下线错误码集合 — 触发踢下线 UI 提示
|
||||
static const Set<int> kickOffCodes = {
|
||||
loggedInAnotherDevice,
|
||||
signingMethodError,
|
||||
parsingKeyError,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||
|
||||
/// JWT token 过期时间解析
|
||||
///
|
||||
/// 使用 dart_jsonwebtoken 解码 JWT payload,提取 `exp` claim 返回过期时间。
|
||||
/// 返回 null 表示无法解析(非 JWT 格式或缺少 exp 字段)。
|
||||
///
|
||||
/// 只读取 payload,不验证签名(验证是服务端的事)。
|
||||
///
|
||||
/// 用于 [ApiConfig.onGetTokenExpiry] 回调,启用 token 主动刷新:
|
||||
/// 距过期不足阈值时提前刷新,避免带过期 token 发请求或重连。
|
||||
///
|
||||
/// ```dart
|
||||
/// final expiry = parseJwtExpiry('eyJhbGci...');
|
||||
/// if (expiry != null) {
|
||||
/// final remaining = expiry.difference(DateTime.now());
|
||||
/// print('Token expires in ${remaining.inMinutes} min');
|
||||
/// }
|
||||
/// ```
|
||||
DateTime? parseJwtExpiry(String token) {
|
||||
try {
|
||||
final jwt = JWT.decode(token);
|
||||
final payload = jwt.payload;
|
||||
if (payload is! Map<String, dynamic>) return null;
|
||||
|
||||
final exp = payload['exp'];
|
||||
if (exp is! int) return null;
|
||||
return DateTime.fromMillisecondsSinceEpoch(exp * 1000);
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user