electron+vue3写了一个小项目,实现了一个文件下载功能
存在的问题
打包后,应用下载文件崩溃
代码
javascript
// 渲染进程
window.electron.ipcRenderer.invoke(
'save-file', {
'path': r.filePath,
'fileurl': previewUrl,
}
).then(response => {
console.log('response --------------');
console.log(response);
})
// 主进程
ipcMain.handle('save-file', (event, args) => {
// process.crash()
try {
// 下载保存文件
console.log('axios args.fileurl ------------');
console.log(args.fileurl);
return downloadFile(args.fileurl, args.path)
} catch (error) {
console.log('error ---------------------------')
console.log(error)
return 'save-file 出错了: \n' + error.toString()
}
});
// 工具文件
import axios from 'axios'
import fs from 'fs/promises'
export function downloadFile(downloadUrl, downloadPath) {
try {
return axios.get(downloadUrl, {
method: 'GET',
headers: {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36",
"Referer": downloadUrl,
},
responseType: 'arraybuffer'
}).then(res => {
console.log('下载成功')
return fs.writeFile(downloadPath, res.data, "binary").then(r => {
console.log('保存成功')
return fs.stat(downloadPath)
});
}).catch(e => {
console.log('e ------------------')
console.log(e)
return e
});
} catch (error) {
console.log('error ---------------------------')
console.log(error)
return 'downloadFile 出错了: \n' + error.toString()
}
}
解决思路
首先,要复现,我测试了自己的笔记本电脑,双系统都没问题,没办法复现这个bug,但是测试那边两台电脑都能复现,测试是在外地!我只好又找了一台闲置电脑,还好复现出来了,否则只能回家试试自己的电脑了
第二,找到问题所在,打包后 console.log 就看不到了,我想办法记录日志,看了官方的crashReporter,还有不少人推荐,我正好全栈,就搞了个接口接收日志,但是没有任何报错。后来试了electron-log,记录在用户本地,真香,简单好用,以后有需要直接搞个接口上传log文件就好了!还是没报错!但是我锁定了有问题的那一行代码,就是 axios.get(downloadUrl, { 这里崩溃的!
第三,想办法换掉axios!试了第三方electron下载库,electron-download、electron-dl、都很难用,文档少,搜索结果更少,自己摸索半天也没跑起来,继续换electron-download-manage,但是这个东西调用很麻烦!换request下载,和axios比较像,还是不行!我觉得我的方向可能错了,灵机一动,把axios下载放在渲染进程里面,下载好的数据传递给主进程!好了!
代码
javascript
// 渲染进程
axios.get(previewUrl, {
method: 'GET',
responseType: 'arraybuffer'
}).then(res => {
console.log('下载成功')
console.log('下载成功')
console.log('下载成功')
console.log(typeof res.data)
window.electron.ipcRenderer.invoke(
'save-file', {
'data': res.data,
'path': r.filePath,
}
).then(response => {
console.log('response --------------');
console.log(response);
})
// 主进程
ipcMain.handle('save-file', (event, args) => {
try {
log.info('event, args ------------');
log.info(event, args);
// 保存文件
return saveFile(args.data, args.path)
} catch (error) {
log.info('error ---------------------------')
log.info(error)
return 'save-file 出错了: \n' + error.toString()
}
});
// 工具js
import fs from 'fs/promises'
import log from 'electron-log'
import { Buffer } from 'buffer'
export function saveFile(data, downloadPath) {
log.info('saveFile ----------------------- 0')
try {
log.info('saveFile ----------------------- 1')
return fs.writeFile(downloadPath, Buffer.from(data), "binary").then(r => {
log.info('保存成功')
return fs.stat(downloadPath)
});
} catch (error) {
log.info('saveFile ----------------------- 3')
log.info('error ---------------------------')
log.info(error)
throw new Error('saveFile出错了:' + error.toString()) // 将错误包装成新的Error对象并抛出,让调用者知道发生了错误
}
}
中间还发生了一个小插曲
Error occurred in handler for 'save-file':
TypeError [ERR_INVALID_ARG_TYPE]:
The "data" argument must be of type string or an instance of
Buffer, TypedArray, or DataView. Received an instance of ArrayBuffer
所以才有了Buffer.from(data)
感谢文心一言,感谢我自己!