整了一下午,百度不是没有答案,就是要使用第三方库,同事也迷迷糊糊,只能自己来,最后只能取巧完成这个需求
环境:node,使用express搭建服务器
前端使用 element-plus 的 el-upload
解决方法
- 自定义上传,用于修改文件名
- 因为el-upload的默认上传编码使用的是gbk,但是node并不能解析gbk编码(node默认使用utf-8),所以当中文文件名的文件传至后端时文件名会变成乱码(其实node有提供将buffer转成gbk编码的方法)
- 正因为node有提供将buffer转成gbk编码的方法,所以才能取巧,最后其实也不用转成gbk编码
直接上代码
- 在beforeUpload中修改文件名,将文件名改成uint16Array数组的形式再使用序列化转为字符串
<template>
<div class="daily">
上传日报:
<el-upload ref="uploadRefs" drag name="files"
:before-upload="beforeUpload" :show-file-list="true">
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
上传日报 <em>点击上传</em>
</div>
</el-upload>
</div>
</template>
<script setup lang='ts'>
import { UploadFilled } from '@element-plus/icons-vue'
import { ref } from 'vue';
import { dailyUpload } from '@/service/api'
const uploadRefs = ref()
// 上传前拦截,实现自定义上传,一定要返回false
const beforeUpload = async (rawFile) => {
const f = new File([rawFile], JSON.stringify(str2charcode(rawFile.name)))
dailyUpload({ files: f }).then((res) => {
console.log(res);
// 调用上传接口成功后执行后续操作
})
return false
}
// 将字符串转为 unit16Array,charCodeAt的详情请看MDN文档
function str2charcode(str: String): number[] {
const arr = []
for (const key of str) {
arr.push(key.charCodeAt())
}
return arr
}
</script>
- 此时后端接受到的文件的文件名应该是一个数组字符串
- 后端使用的是multer处理上传文件
module.exports.dailyUpload = async (req, res, next) => {
try {
// 使用TextDecoder将Uint16Array的文件名转为中文
const fileName = new TextDecoder("utf-16").decode(new Uint16Array(JSON.parse(req.file.originalname)).buffer);
// 重命名文件
await rename("./public/daily/" + req.file.filename, "./public/daily/" + fileName);
// 在MongoDB中保存上传记录
const dailyModel = new Daily({ time: Date.now(), url: fileName });
await dailyModel.save();
res.status(201).json({ error: 0, data: { url: fileName } });
} catch (err) {
res.status(500).json({ error: 1, message: err });
}
};
- 这时候文件名就是中文了