跳到正文
灵动桌面框架
Esc
本栏目菜单

错误处理

灵动桌面框架使用结构化错误系统(src-tauri/src/error.rs),确保错误信息从后端安全传递到前端。

两种错误类型

类型用途使用位置
AppError内部业务错误(thiserror 枚举)Service 层、Database 层
CommandErrorIPC 返回错误,结构为 { code, message }Command 层(前端可见)

AppError 的变体:

#[derive(Debug, Error)]
pub enum AppError {
    #[error("IO 错误: {0}")]
    Io(#[from] std::io::Error),
    #[error("数据库错误: {0}")]
    Database(#[from] rusqlite::Error),
    #[error("JSON 解析错误: {0}")]
    Json(#[from] serde_json::Error),
    #[error("未找到: {0}")]
    NotFound(String),
    #[error("参数无效: {0}")]
    InvalidInput(String),
    #[error("{0}")]
    Custom(String),
}

Io、Database、Json 带 #[from],对应的底层错误可直接用 ? 转成 AppError。

错误转换链

rusqlite / io / serde_json 错误 → AppError → CommandError → 前端 catch

impl From<AppError> for CommandError 按变体映射错误码(见 错误码速查),message 取 AppError 的 Display 文本(含「未找到: 」「参数无效: 」等前缀)。Command 中统一这样转换:

ConfigService::get(&state.db, &key).map_err(|e| e.into())

CommandError 实现了 Serialize,Tauri 会把它序列化成 JSON 对象作为 invoke 的拒绝值,前端 catch 拿到的就是 { code, message } 对象。error.rs 中另有 From<CommandError> for String 与 From<AppError> for String,仅为向后兼容保留。

前端错误处理

import { message } from 'antd'
import { configApi, type CommandError } from '@/lib/api'

try {
  const theme = await configApi.get('theme')
} catch (e) {
  const err = e as CommandError
  // err: { code: "NOT_FOUND", message: "未找到: 配置项 'theme' 不存在" }
  message.error(err.message)
}

WARNING

src/lib/api/client.ts 中的 parseCommandError / getErrorMessage / getErrorCode 目前按“错误是 JSON 字符串”解析,传入对象时会退化为 { code: "UNKNOWN", message: "[object Object]" };同理 String(e) 也只会得到 [object Object]。读取后端错误时请直接访问 code / message 字段。

规范

  • 禁止使用 unwrap() — 使用 ? 运算符
  • 禁止使用 panic!() — 返回 Err(AppError::...)
  • Mutex 加锁失败用 map_err(|e| AppError::Custom(e.to_string())) 转换,不要 lock().unwrap()
  • 所有错误必须处理或向上传播