[eggjs/egg]eggjs 如何接收node上传的文件流

2024-08-05 538 views
3

eggjs 接收不到 ctx.multipart(),怀疑是前端代码参数有问题,但是网上找了很多参数的写法,都接收不到,不知道该怎么写了。

前端代码:

// electron nodejs 环境,根据文件路径,把文件上传到服务器(静默上传)
const FormData = require("form-data");
let data = new FormData();
data.append("file1", fs.createReadStream("D:\\111.tx"), "111.tx");
data.append("file2", fs.createReadStream("D:\\222.tx"), "222.tx");

Axios.post("/api/uploadFile", data, {
  headers: {
    "x-csrf-token": Util.GetCookie("csrfToken"),
    "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
  },
});

eggjs代码:

// 处理 /api/uploadFile ,参数是controller传递过来的 this.ctx
static UpLoadFile(ctx: any) {
  const parts = ctx.multipart();   // 此处接收不到parts
  let part;
  while ((part = await parts()) != null) {
    if (part.length) {
      // 这是 busboy 的字段
      console.log('field: ' + part[0]);
      console.log('value: ' + part[1]);
      console.log('valueTruncated: ' + part[2]);
      console.log('fieldnameTruncated: ' + part[3]);
    } else {
      // 这时是用户没有选择文件就点击了上传(part 是 file stream,但是 part.filename 为空)
      // 需要做出处理,例如给出错误提示消息
      if (!part.filename) throw "上传参数不对";
      // // part 是上传的文件流
      // console.log('field: ' + part.fieldname);
      // console.log('filename: ' + part.filename);
      // console.log('encoding: ' + part.encoding);
      // console.log('mime: ' + part.mime);
      // 文件处理,上传到云存储等等
    }
  }
}

要实现的功能:electron 检测到本地文件有变更后,直接把文件上传到服务器

回答

2

这要给出一个最小的可复现的demo, 你这样说没办法定位问题的

3

Hello @Yinyiran. Please provide a reproducible example following the instruction.

Issues labeled by Need Reproduce will be closed if no activities in 7 days.


@Yinyiran,请根据这个说明提供最小可复现代码。

如果在 7 天内没有进展会被自动关闭。

6

已经修改了,想要的功能就是:nodejs环境的多文件上传,上一次描述不清晰,不好意思。

3

File模式需要手动选择文件,需求是静默上传,不要手动操作

8

跟是不是手动上传没啥关系

6

不手动选择file,手写一个formData的话,ctx.request.files 长度是0,还是接收不到文件,是我formData写的不对么?

9

这就是 HTTP 协议,跟是不是手动上传没关系,只可能是你代码写错。

6

我想知道那里错了,网上没有找不到解决方案

6

我也想知道你哪里错了,可是你不给可复现方式,我也爱莫能助。

大概率是你的 content-type 等不对,你可以断点 egg-multipart 代码调试下就知道。(PS:如果你看了它的源码,你就知道 file 和 stream,只是处理的语法糖,跟你前面 HTTP 是不是手动的没有一点关系)

3

大哥,根据那几个代码就能复现,

const FormData = require("form-data");
let data = new FormData();
data.append("file1", fs.createReadStream("D:\\111.tx"), "111.tx");
data.append("file2", fs.createReadStream("D:\\222.tx"), "222.tx");

Axios.post("/api/uploadFile", data, {
  headers: {
    "x-csrf-token": Util.GetCookie("csrfToken"),
    "Content-Type": `multipart/form-data; boundary=${data._boundary}`,
  },
});

在egg当中,ctx.request.files 是空数组,接受不到file;

4

请根据这个说明提供最小可复现代码仓库

9
let parts = this.ctx.multipart({ autoFields: true });

加上autoFields: true 参考文档

7
你期待的是什么?

在nodejs环境中根据文件的本地路径,上传文件到eggjs服务中

实际上的情况是?

egg服务无法接收到前端的文件数据,网上找了很多方法,都失败了,希望大佬能帮忙指点一下错误的地方,万分感谢

可复现代码仓库地址

https://github.com/Yinyiran/syncfile

3

@Yinyiran

  1. 改为 file mode
  2. 用 curl 验证是否能正确上传
  3. 抓包你的前端代码的 HTTP 请求,分析是不是 content-type 啥的错了
9

先关了,有进展的话可以随时再开。

这种问题,应该二分排查,你启动 Egg 后,用 curl 或 supertest 单测去先看 Egg 有没有问题。

然后再看 client 侧是不是传错内容了。 就是标准 HTTP 协议来着。

7

我也有类似需求,我的实现方法可以分享下供参考。

发送方:我也使用的是 form-data,最后发送时用的是 formData.submit()

接收方:正如天猪说的,用 file mode,直接在 controller 里用 ctx.request.files 就可以收到文件

9

最近刚好也遇到这个问题,我做个小总结: 如果上传是File模式,要做如下配置,这种情况可以获取到ctx.request.files

// config/config.default.js
config.multipart = {
  mode: 'file',
};

而楼主用的是Stream的模式,这种情况下ctx.request.files是没有值的

// 单个文件可以通过如下方式获取
const stream = await ctx.getFileStream();

具体可以看官方文档:https://eggjs.github.io/zh/guide/upload.html

8

egg正常接受到前端上传的文件(form-data 发送请求),现在egg传给后端,参数如何写? //Controller async uploadFile() { const {ctx, service} = this; const file = await ctx.getFileStream(); ctx.body = await service.performanceTest.performanceTool.uploadFile.uploadFile(file); }

// Service ctx.curl()参数 { host: app.config.apiPath.host, data, method: 'POST', streaming: true, headers: { 'content-type': 'multipart/form-data' } };

// config配置 config.multipart = { mode: 'stream', whitelist: ['.jmx', '.csv'], fileSize: '50mb', };

// 报错 bad request。