koa-multer和form-data处理文件上传、接收

25 阅读2分钟

踩坑:form-data既有专门的库也有node自带的,它们处理的数据类型是不同的,如下:
Node 18 以后:
Web FormData → 只能吃 Blob
form-data 库 → 才能吃 Buffer
自带的form-data直接用就行(const formData = new FormData()),不需要额外引入。
使用form-data库的话需要先安装,然后引入,最后才能用,如下: npm i form-data const FormData = require("form-data") const formData = new FormData()
tips:推荐使用form-data库不要用node自带的

Koa 默认 不解析 multipart/form-data 请求体,需要 用安装@koa/multer

  1. 文件数据挂载在ctx.request.file
  2. 文本字段在 ctx.request.body!(需要安装koa-bodyparser插件才能接收)

前端

 const handleFileSelect = async (event) => {
        const file = event.target.files[0];
        if (!file) return;

        if (!file.type.match('image.*')) {
            alert('请选择图片文件');
            return;
        }
        try {
            const result = await translateImageFileApi(file, sourceLanguage, targetLanguage);
            console.log("result", result);
            setTranslatedText(result.content[0].dst);
        } catch (error) {
            console.error('OCR error:', error);
            alert('OCR识别失败');
        } finally {
            setIsTranslating(false);
        }
    };
    
    
    
async function translateImageFileApi(file, fromLang = 'auto', toLang = 'zh') {
    if (!file) {
        throw new Error('请提供图片文件');
    }

    // 1. 创建 FormData
    const formData = new FormData();
    formData.append('image', file);        // 字段名必须是 'image'
    formData.append('from', fromLang);     // 文本参数
    formData.append('to', toLang);         // 文本参数

    try {
        const response = await axios.post(
            `/ecTranslationApi/translateImageFile`, // 替换为你的 Koa 地址
            formData,
            {
                headers: {
                    // 不要写 'Content-Type': 'multipart/form-data'
                    // 让 axios 自动设置正确的 boundary
                }
            }
        );
        console.log("前端收到的响应数据:",response);
        return response.data;
    } catch (error) {
        console.error('图片翻译失败:', error);
        throw error;
    }
}    

后端

//安装相应的包
npm i @koa/multer multer
npm i form-data
npm i koa-bodyparser

//引入对应的包
const bodyParser = require('koa-bodyparser'); // 解析 JSON 和 form-urlencode
const multer = require('@koa/multer');
const FormData = require('form-data');

// 配置 multer(内存存储,不写磁盘)
const upload = multer({
    storage: multer.memoryStorage()
});

async function translateImage(file, fromLang = 'auto', toLang = 'zh') {
    try {
        const accessToken = await getAccessToken();
        const formData = new FormData();
        formData.append('image', file.buffer, {
            filename: 'image.jpg', // 或 image.png / image.webp
            contentType: 'image/jpeg' // 可选,但建议匹配
        });
        formData.append('from', fromLang);
        formData.append('to', toLang);
        formData.append('v', 3);

         //既有param参数又有body参数,传递方式如下
        const url = `${serverConfig.BaiduTranslateConfig.imageTranslateUrl}?access_token=${accessToken}`;

        const response = await axios.post(url, formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            },
        });
        console.log("response", response);
    } catch (error) {
        console.error('图片翻译请求失败:', error.response?.data || error.message);
        return {
            success: false,
            error: '网络请求失败'
        };
    }
}

async function translateImageFile(ctx) {
    try {

        console.log('ctx.request.file:', ctx.request.file);
        console.log('ctx.request.body:', ctx.request.body);
        // 1. 获取上传的文件
        const file = ctx.request.file; // 注意:是 ctx.req.file,不是 ctx.request.body
        if (!file) {
            ctx.status = 400;
            ctx.body = { success: false, error: '缺少 image 文件' };
            return;
        }

        // 2. 获取文本参数(from / to)
        const from = ctx.request.body.from || 'auto';
        const to = ctx.request.body.to || 'zh';

        // 3. 验证文件类型(可选但推荐)
        const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp'];
        if (!allowedMimeTypes.includes(file.mimetype)) {
            ctx.status = 400;
            ctx.body = { success: false, error: '仅支持 JPG、PNG、WebP 格式' };
            return;
        }

        // 4. 调用百度图片翻译
        const result = await translateImage(file, from, to);

        console.log("图片翻译result", result);

        // 5. 返回结果
        ctx.body = result;
    } catch (error) {
        console.error('服务器内部错误:', error);
        ctx.status = 500;
        ctx.body = { success: false, error: '服务器内部错误' };
    }
}

重点

前端:要构造multipart/form-data 【使用web的form-data】
后端koa/multer:负责“解析” multipart/form-data
后端再发请求时:重新“构造” multipart/form-data【使用form-data库】

最终对照表(记住这个)

位置用什么
React / 浏览器原生 FormData
Koa 接收文件multer
Koa → 第三方 APIform-data
axios (Node)form-data