项目背景:【vue3+tauri+rust】
由于Safari对于下载总是有诸多阻拦,目前需求windows+mac可以实现:
- 后端返回的url文件可以下载;
- 前端根据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)
}