统一异常处理

import yueyang.vostok.data.exception.*;
import yueyang.vostok.file.exception.*;
import yueyang.vostok.office.exception.*;
import yueyang.vostok.cluster.*;
import yueyang.vostok.cluster.exception.*;
import yueyang.vostok.config.exception.*;

// Data 模块
try {
    Vostok.Data.findAll(User.class);
} catch (VKSqlException e) {
    // SQL_ERROR / SQL_TIMEOUT / SQL_CONSTRAINT / SQL_SYNTAX / SQL_CONNECTION
    log.error("SQL error: {} - {}", e.getCode(), e.getMessage());
} catch (VKPoolException e) {
    log.error("Pool exhausted: {}", e.getMessage());
} catch (VKTxException e) {
    log.error("Transaction error: {}", e.getMessage());
} catch (VKException e) {
    // 所有其他 Vostok 异常基类
    log.error("Vostok error: {} {}", e.getCode(), e.getMessage());
}

// File 模块
try {
    Vostok.File.read("missing.txt");
} catch (VKFileException e) {
    log.error("File error: {} {}", e.getCode(), e.getMessage());
}

// Office 模块
try {
    Vostok.Office.readWordText("word/orders.docx");
} catch (VKOfficeException e) {
    log.error("Office error: {} {}", e.getCode(), e.getMessage());
}

// Cluster 模块
try {
    Vostok.Cluster.broadcast("order.created", "{}".getBytes()).join();
} catch (VKClusterException e) {
    log.error("Cluster error: {} {}", e.getCode(), e.getMessage());
}

Data 模块错误码(VKErrorCode)

错误码枚举触发场景
DK-400INVALID_ARGUMENT传入参数非法(null 主键、空包名等)
DK-401NOT_INITIALIZED模块未初始化时调用操作
DK-402CONFIG_ERROR配置项缺失或错误(无 url/username 等)
DK-410META_ERROR实体元数据解析失败(@VKEntity 配置错误)
DK-500SQL_ERRORSQL 执行通用错误
DK-501SQL_TIMEOUTSQL 执行超时
DK-502SQL_CONSTRAINT唯一约束、外键约束等违反
DK-503SQL_SYNTAXSQL 语法错误
DK-504SQL_CONNECTION数据库连接失败
DK-510SCAN_ERROR实体包扫描失败
DK-520POOL_ERROR连接池错误(耗尽、泄漏检测等)
DK-530TX_ERROR事务开启/提交/回滚失败
DK-540CACHE_ERROR缓存操作错误

Data 原生 SQL 场景(executeQuery / executeUpdate)

场景错误码说明
SQL 语法错误(如 SELEC)DK-503 SQL_SYNTAXVKExceptionTranslator 按 SQLState=42xx 映射
数据库连接异常DK-504 SQL_CONNECTION连接断开、网络不可达等连接类错误
执行超时DK-501 SQL_TIMEOUTqueryTimeoutMs 或事务剩余超时控制
try (DataResult rs = Vostok.Data.executeQuery("SELEC id FROM t_user")) {
    // no-op
} catch (VKSqlException e) {
    // 常见:DK-503 SQL_SYNTAX
    log.error("raw sql failed: {} {} sqlState={}", e.getCode(), e.getMessage(), e.getSqlState());
}

Data 模块异常类型

异常类包路径对应错误码
VKExceptiondata.exception所有运行时异常基类
VKArgumentExceptiondata.exceptionDK-400
VKStateExceptiondata.exceptionDK-401
VKConfigExceptiondata.exceptionDK-402
VKMetaExceptiondata.exceptionDK-410
VKSqlExceptiondata.exceptionDK-500 ~ DK-504
VKScanExceptiondata.exceptionDK-510
VKPoolExceptiondata.exceptionDK-520
VKTxExceptiondata.exceptionDK-530

File 模块错误码(VKFileErrorCode)

错误码枚举触发场景
FK-400INVALID_ARGUMENT路径参数为 null 或空
FK-401NOT_INITIALIZEDFile 模块未初始化
FK-402CONFIG_ERRORbaseDir 配置错误
FK-403STATE_ERROR状态异常(如已关闭)
FK-404NOT_FOUND文件或目录不存在
FK-410PATH_ERROR路径越界(尝试访问 baseDir 之外)
FK-500IO_ERROR文件读写 IO 错误
FK-520SECURITY_ERROR安全错误(Zip Slip 路径穿越)
FK-530UNSUPPORTED当前存储后端不支持该操作
FK-540ZIP_BOMB_RISKZIP 炸弹限制触发(解压比过高)
FK-550IMAGE_DECODE_ERROR图片解码失败
FK-551IMAGE_ENCODE_ERROR图片编码失败
FK-552IMAGE_LIMIT_EXCEEDED图片尺寸/像素超出限制
FK-553UNSUPPORTED_IMAGE_FORMAT不支持的图片格式
FK-560READ_ONLY_ERROR存储处于只读模式,写操作被拒绝
FK-561ENCRYPT_ERROR文件加密/解密失败
FK-562GZIP_ERRORGZip 压缩/解压失败

File 模块异常类型

异常类包路径说明
VKFileExceptionfile.exceptionFile 模块所有异常的基类,包含 VKFileErrorCode

Web 模块(@VKApi 注解路由)错误返回说明

场景HTTP 状态返回体
参数绑定失败(缺少必填 Query/Header/Cookie、类型转换失败)400统一返回 VKWebResultstatusCode=400
控制器方法执行异常500(默认)统一返回 VKWebResult,默认错误信息为 Internal Server Error
业务主动返回 VKWebResult.of(418, ...)418HTTP 状态码与 statusCode 保持一致
// 绑定失败示例:GET /api/user?id=abc,id 需要 long
{
  "statusCode": 400,
  "errorMessage": "Query param 'id' is required",
  "data": null,
  "requestCostMs": 1,
  "traceId": "trace-7b3c",
  "requestTime": 1741075200000,
  "responseTime": 1741075200001
}

Office 模块错误码(VKOfficeErrorCode)

错误码枚举触发场景
OF-400INVALID_ARGUMENT参数非法(空路径、空 consumer 等)
OF-402CONFIG_ERROROffice 配置不合法
OF-403STATE_ERROR运行状态不满足(如非 local 文件模式)
OF-404NOT_FOUNDsheet 或资源不存在
OF-500IO_ERRORIO 操作失败
OF-530UNSUPPORTED_FORMAT不支持的 Office 格式(当前仅 .xlsx / .docx / .pptx / .pdf)
OF-564PARSE_ERROROffice 文档解析失败(Excel/Word/PPT/PDF)
OF-565WRITE_ERROROffice 文档写入失败(Excel/Word/PPT/PDF)
OF-566LIMIT_EXCEEDED超过行列/字数/图片/大小限制
OF-567SECURITY_ERROR安全检测失败(路径/魔数/XXE/压缩安全)

Office 模块异常类型

异常类包路径说明
VKOfficeExceptionoffice.exceptionOffice 模块统一异常,包含 VKOfficeErrorCode

Office Excel 模板常见错误场景

场景错误码说明
模板后缀不是 .xlsxOF-530 UNSUPPORTED_FORMATrenderExcelTemplate 仅支持 .xlsx
循环起止标记不匹配 / 缺少结束标记OF-564 PARSE_ERROR例如只有 {{#items as item}} 没有 {{/items}}
模板展开后行数超过限制OF-566 LIMIT_EXCEEDEDVKExcelTemplateOptions.maxExpandedRows 或全局限制触发
输出文件大小超过限制OF-566 LIMIT_EXCEEDEDVKExcelTemplateOptions.maxOutputBytes 或全局限制触发
模板文件伪装 / XXE / 压缩安全风险OF-567 SECURITY_ERROR路径、魔数、XML 与解包安全检查命中

Office 异步任务错误场景

try {
    String jobId = Vostok.Office.submitJob(
        VKOfficeJobRequest.create(() -> {
            throw new RuntimeException("convert failed");
        })
    );
    Vostok.Office.awaitJob(jobId, 30000);
} catch (VKOfficeException e) {
    // 常见:STATE_ERROR(运行态不满足)、WRITE_ERROR(任务执行失败)
    Vostok.Log.error("office job error: {} {}", e.getCode(), e.getMessage());
}

// 回调无订阅者时,可通过 dead-letter 接收“未处理通知”
Vostok.Office.onJobDeadLetter(n ->
    Vostok.Log.warn("office dead-letter: {} {}", n.jobId(), n.status()));

Cluster 模块错误码(VKClusterErrorCode)

错误码枚举触发场景
CL-400INVALID_ARGUMENTtopic 为空、listener 为空、消息参数非法
CL-402CONFIG_ERRORnodeId / clusterSecret / 端口等配置错误
CL-403STATE_ERRORCluster 未初始化就调用运行时方法
CL-404NOT_FOUND节点或资源不存在
CL-451AUTH_ERRORclusterName 不一致、共享密钥 HMAC 校验失败
CL-500IO_ERROR端口绑定失败、连接 IO 异常
CL-560PROTOCOL_ERROR非法帧、非法长度、协议版本不兼容
CL-566LIMIT_EXCEEDED超过最大节点数、消息体超限
CL-568BROADCAST_TIMEOUT预留给广播超时场景的错误码

Cluster 典型错误场景

场景错误码说明
节点间 clusterSecret 不一致CL-451 AUTH_ERROR握手时 HMAC 校验失败,连接立即断开
clusterName 不一致CL-451 AUTH_ERROR不同集群直接拒绝互联
广播 payload 超过 maxMessageBytesCL-566 LIMIT_EXCEEDED广播发送前直接拒绝
收到非法帧或帧长度异常CL-560 PROTOCOL_ERROR协议层拒绝处理并记入 protocolErrors
模块未初始化就调用 nodes() / broadcast()CL-403 STATE_ERROR必须先执行 Vostok.Cluster.init(...)
try {
    Vostok.Cluster.init(new VKClusterConfig()
        .clusterName("prod-order")
        .clusterSecret("wrong-secret")
        .nodeId("node-01")
        .bindHost("127.0.0.1")
        .bindPort(18888));
    Vostok.Cluster.broadcast("order.created", "{}".getBytes()).join();
} catch (VKClusterException e) {
    Vostok.Log.error("cluster failed: {} {}", e.getCode(), e.getMessage());
}

Config 模块错误码(VKConfigErrorCode)

错误码枚举触发场景
CK-400INVALID_ARGUMENT传入参数非法
CK-402CONFIG_ERROR配置自身错误
CK-404KEY_NOT_FOUND必需配置项不存在
CK-420VALIDATION_ERROR配置值未通过 Validator 校验
CK-500IO_ERROR配置文件读取 IO 错误
CK-510PARSE_ERROR配置文件解析失败(格式错误)

Config 模块异常类型

异常类包路径说明
VKConfigExceptionconfig.exceptionConfig 模块所有异常的基类,包含 VKConfigErrorCode

获取错误码

// VKException 及子类
try {
    Vostok.Data.insert(entity);
} catch (VKException e) {
    VKErrorCode code = e.getCode();  // 枚举值
    String msg = e.getMessage();
    // 例:code = SQL_CONSTRAINT, code.name() = "SQL_CONSTRAINT"
}

// VKFileException
try {
    Vostok.File.read("x.txt");
} catch (VKFileException e) {
    VKFileErrorCode code = e.getCode();
    // 例:code = NOT_FOUND
}

// VKConfigException
try {
    Vostok.Config.getString("required.key");
} catch (VKConfigException e) {
    VKConfigErrorCode code = e.getCode();
}