人人都会AI编程

命令模式(Command):前端调用 Rust 函数,请求 - 响应式交互

更新时间:2026-07-11

在 Tauri 中,前后端交互的核心机制就是命令模式(Command)。这是一种经典的请求-响应模式:前端发起调用,后端执行逻辑并返回结果,整个过程清晰、可预期,并且全程受类型系统约束。


命令是什么?

简单来说,命令就是你在 Rust 端用 #[tauri::command] 宏标记的普通函数。标记后,这个函数会自动暴露给前端 JavaScript,前端可以通过一个统一的 invoke 方法来调用它,就像调用一个异步 API 一样。

// Rust 端:定义一个命令
#[tauri::command]
fn greet(name: String) -> String {
    format!("你好,{}!", name)
}
// 前端:调用这个命令
import { invoke } from '@tauri-apps/api/core';
const greeting = await invoke('greet', { name: '小明' });
console.log(greeting); // 输出:你好,小明!

调用关系非常直观:前端传入参数,Rust 处理完返回结果,前端拿到结果,一次交互就结束了。


命令的本质:请求-响应,不建立长连接

与事件监听不同,命令是一次性交互。前端调用一次,后端响应一次,状态不会保持。这种模式特别适合:

  • 读取/写入配置
  • 查询数据
  • 执行单次文件操作
  • 触发计算任务(计算完后直接返回结果)

它就像调用一个 HTTP API,只是通信发生在本地的 Rust 进程和 WebView 之间,没有网络延迟,也不需要处理连接断开的问题。


命令的参数与返回类型:类型安全是标配

Tauri 在序列化参数和返回值时使用 JSON(通过 Serde),所以你只需使用普通的 Rust 类型,Tauri 会自动帮你处理转换:

  • 前端传 { name: "小明" } → Rust 收到 String 类型的 name
  • Rust 返回 "Hello" → 前端拿到 JavaScript 字符串。

如果是更复杂的数据结构,只需确保 Rust 类型实现了 Serialize/Deserialize

#[derive(serde::Serialize)]
struct User {
    id: i32,
    username: String,
}

#[tauri::command]
fn get_user(id: i32) -> Result<User, String> {
    // ... 获取用户逻辑 ...
    Ok(User { id, username: "alice".into() })
}

前端调用后拿到的就是 { id: 1, username: "alice" } 这个 JavaScript 对象,体验完全原生。


错误处理:用 Result 自然表达

命令可以返回 Result<T, E>,Tauri 会自动将 Err 变体转化为前端能够捕获的错误:

#[tauri::command]
fn read_file(path: String) -> Result<String, String> {
    std::fs::read_to_string(&path).map_err(|e| e.to_string())
}
try {
  const content = await invoke('read_file', { path: '/some/file.txt' });
  console.log(content);
} catch (error) {
  console.error('读文件失败:', error); // 错误消息是 Rust 那边传过来的字符串
}

这种模式让错误处理路径和前端异步代码的 try-catch 完美契合,不会丢失错误信息。


命令的注册:让前端“知道”有哪些命令

Rust 端定义了命令后,必须在应用构建时注册它们:

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet, get_user, read_file])
        .run(tauri::generate_context!())
        .expect("启动失败");
}

所有注册的命令都会被安全访问控制策略检查:如果某个需要特殊权限的命令没有在配置文件中声明对应的能力,调用时就会被拦截。这确保了即使前端代码中调用了某个命令,没有经过授权的动作也无法执行。


命令模式的实用建议

  1. 注意参数大小:命令通过 JSON 序列化传递,如果参数是一个巨大的文件数据,考虑使用文件路径而非内容直接传递。
  2. 避免长时间阻塞:命令默认在主线程执行,如果处理需要较长时间,应使用 async 命令或将计算放入 tauri::async_runtime::spawn_blocking
  3. 命令命名清晰:使用动词开头,比如 read_filesave_configfetch_user,让前端调用代码一目了然。

命令模式是 Tauri 中最基础、最常用的交互方式,它把前端发起请求、后端执行逻辑这种最自然的需求,用类型安全、低开销的方式实现了。对于大多数工具型应用,90% 的前后端通信都可以通过命令完成。