前端文件上传,文件名为中文,node显示文件名乱码

1,482 阅读1分钟

整了一下午,百度不是没有答案,就是要使用第三方库,同事也迷迷糊糊,只能自己来,最后只能取巧完成这个需求

环境:node,使用express搭建服务器

前端使用 element-plus 的 el-upload

解决方法

  1. 自定义上传,用于修改文件名
  2. 因为el-upload的默认上传编码使用的是gbk,但是node并不能解析gbk编码(node默认使用utf-8),所以当中文文件名的文件传至后端时文件名会变成乱码(其实node有提供将buffer转成gbk编码的方法)
  3. 正因为node有提供将buffer转成gbk编码的方法,所以才能取巧,最后其实也不用转成gbk编码

直接上代码

  1. 在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>

  1. 此时后端接受到的文件的文件名应该是一个数组字符串

image.png

  1. 后端使用的是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 });
      }
    };
  1. 这时候文件名就是中文了