【vue3+tauri+rust】如何实现下载文件mac+windows

项目背景:【vue3+tauri+rust】

由于Safari对于下载总是有诸多阻拦,目前需求windows+mac可以实现:

  1. 后端返回的url文件可以下载;
  2. 前端根据dom元素生成的PDF报告可以下载(无远程URL);
我的尝试:
  • 方法一:window.open(url) 。需要远程url可实现windows+1,但浏览器有不安全警告,且Mac无反应。❌

  • 方法二:利用tauri插件:

    • 安装 "@tauri-apps/plugin-opener": "^2.2.7",

    • import { openUrl } from '@tauri-apps/plugin-opener';

    • 使用 await openUrl(req_url);

      需要远程url,可实现windows+Mac+1,但浏览器有不安全警告。❌

  • 方法三:返回base64+转为blob+创建a标签点击:

javascript 复制代码
const response = await invoke('get_req', { url: req_url, timeout: 30 });
const blob = base64ToBlob(
  response.data,
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'robot_template.xlsx';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

可实现windows+1+2,不需要远程URL,但Mac无反应。❌

终极大绝招:

实现方式:前端save窗口获取filePath +Rust命令写入磁盘 ,完美避开浏览器拦截,且没有不安全提示,适合所有类型文件!!✅

需求1:

javascript 复制代码
import { open, save } from '@tauri-apps/plugin-dialog';

try {
    // res.data.b64 res.data.title
    const res = await Robot.template();
    if (res.success) {
      const base64 = res.data.b64;
      const fileName = res.data.title || 'robot_template.xlsx';

      // 获取路径
      const filePath = await save({
        defaultPath: fileName,
        filters: [{ name: 'Excel', extensions: ['xlsx'] }],
      });

      if (!filePath) return;

      // Rust写入
      await invoke('save_file', {
        filePath: filePath,
        base64Data: base64,
      });
      ElMessage.success(t('common.success'));
    }
  } catch (e) {
    ElMessage.error('下载失败' + e);
  }

需求2:

javascript 复制代码
import { invoke } from '@tauri-apps/api/core';
import { save } from '@tauri-apps/plugin-dialog';
import jsPDF from 'jspdf';

try {
      // 创建 PDF
      const pdf = new jsPDF({
        orientation: 'portrait',
        unit: 'mm',
        format: 'a4',
      });
      
      // .....省略业务pdf处理逻辑

      // pdf.save(fileName); // Windows可以 Mac不可以
      
	  // 唤起文件保存窗口 用户自定义保存路径
      const filePath = await save({
        defaultPath: fileName,
        filters: [{ name: 'PDF', extensions: ['pdf'] }],
      });
      if (!filePath) return; // 用户取消
      const dataUriString = pdf.output('datauristring');
      const base64 = dataUriString.split(',')[1];
      // Rust写入  
      await invoke('save_file', {
        filePath: filePath,
        base64Data: base64,
      });
      ElMessage.success(t('scene.report.export_success'));
    } finally {
      // 关闭加载提示
      loadingMessage.close();
    }

Rust新增:

rust 复制代码
// tauri.conf.json 
"plugins": {
    "opener": {
      "requireLiteralLeadingDot": false
    }
  }
  
// http.rs
use std::fs::File;
use std::io::Write;
use base64::Engine;

#[tauri::command]
pub fn save_file(filePath: String, base64Data: String) -> Result<String, String> {
    log::info!("写入文件传过来的参数:{filePath}");
    // 写入文件
    let decoded = base64::engine::general_purpose::STANDARD
        .decode(base64Data)
        .map_err( |e| format!("Base64 解码失败: {}", e))?;
    let mut file = File::create(&filePath).map_err( |e| format!("创建文件失败:{}", e))?;
    file.write_all(&decoded).map_err( |e| format!("写入文件失败:{}", e))?;
    
    Ok(filePath)
}
相关推荐
会Tk矩阵群控的小木33 分钟前
基于Python的iMessage短信群发与社媒多账号统一管理系统实现
开发语言·windows·python·新媒体运营·开源软件·个人开发
ryanuo744 分钟前
Mac(M芯片)上进行嵌入式开发遇到的问题
嵌入式硬件·macos·开发板
Jurio.1 小时前
开源 Codex Sticky:在终端 Codex CLI 长对话中始终固定底部输入框
linux·rust·github·开源软件·codex·codex cli
不爱记笔记2 小时前
苹果WWDC 2026全解析:Apple Intelligence+ 性能提升数据一览
macos·ios·wwdc
阿正的梦工坊3 小时前
【Rust】04-借用、引用与切片
java·数据库·rust
福大大架构师每日一题3 小时前
2026年6月TIOBE编程语言排行榜,Go语言排名第13,Rust语言排名12。关于Rust已进入平台期的报道似乎为时过早。
开发语言·golang·rust
雾沉川3 小时前
Nano11 25H2 精简版 Windows11 系统介绍与部署实操教程
windows
咸甜适中3 小时前
rust语言学习笔记Trait(十六)Error(错误)
笔记·学习·rust
guyoung3 小时前
BoxAgnts 工具系统(4)——Tool Trait 与并发上下文模型
rust·agent·ai编程
张世争5 小时前
armcc5 c++98 的静态库裁剪大小的方法
windows·静态库·裁剪·armcc