请问form表单提交数据时是否一定要带有file文件上传?对于不带file的form表单,ctx.getFileStream()方法会报错,提示没有发现file文件。ctx.multipart()方法则无法正常继续执行while循环后的代码,


ctx.multipart()是按顺序循环读取流,可是当读取到part.filename==“”(就是没有file文件的时候),就停下来了,while后面的语句不再继续执行。
如果form表单带file文件,则两个方法都是正常的。
请问你们有试过这个问题吗?
没文件你为啥要调用 ctx.getFileStream()?
直接读 ctx.request.body 即可 https://eggjs.org/zh-cn/basics/controller.html#body
如果是form表单提交的数据,通过ctx.request.body拿到是{},空的。
检查 content-type
content-type是这样的:
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryOdQZ2dV579K3avhs
请问有人遇到这个问题?
你 form 设了 enctype?
设置了,enctype="multipart/form-data"
你们可以用一个form表单,测试一下文档中上传多个文件那段代码,form表单有file,但前端提交的时候不带file文件,


如果没有 file 不用设置 enctype,默认是 application/x-www-form-urlencoded
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/form
你这个问题是这样的,一般 multipart 方法都是为了取文件,属性是挂载文件 stream 上的,你这样没文件就要单独去取属性,这个是没有例子的,如果你还是想这样做那可以去看下底层代码的实现去取 field。
如果前端只是上传表单的数据,后端如何获取呢?
必须要确保 file 放到最后,其他 form 字段放到 file 的前面,这样 ctx.getFileStream() 拿到的 stream 上会有 fields 字段。
同样遇到了这样的问题 这个异步根本不出while 也就说while外部及后面的代码不会去执行 都不自己去试一下就发各种demo到文档也是醉了
文档上写的清清楚楚,要放在最后一个,文档看不仔细也是醉了。
感谢各位白忙之中的回复,文档写的很清楚,我也看到了,可能是我的问题写的不清楚,让大家误解了。问题不是在于文件的位置,其实文件的位置在fields的第一个还是最后一个都没有关系,都能获取到fields的值。问题在于form-data提交表单的时候,表单中有一些fields,包含一个文件(用户可选是否上传文件),但是当文件是空的时候,表单提交到服务端,服务端如何获取到这些fields。各位有空可以蛮测试一下。enctype="multipart/form-data“形式提交的form-data表单,服务端是以流的形式接收,当文件是空的,ctx.getFileStream()会直接throw err:nodejs.BadRequestError: Can't found upload file。我想知道是我的用法不对,还是form-data提交表单一定要带文件上传。
while后面的代码是否执行就看while里面怎么写,如果if (!part.filename) {return;}注释掉,不论是否有文件都会执行,不是吗? @phper-chen @atian25
@JohnnyMore 注释掉就会报错,不注释就一直while那了
@ JohnnyMore ,这个问题解决了么?我也卡在这个问题上,要是不行的话,只有分开写了。
我也遇到这样的问题,前端页面有4个上传图片的input,网页需求允许用户可以不选择图片上传,这样后端在接收数据的时候就要判断filename是否为空。
我现在的处理方式是如果判读filename为空,那么就执行part.read() 然后继续后面的循环。
好像真有点问题啊!多文件上传,while循环跳不出来啊,官网的例子,如果上传多个图片,有一个图片没为空。而且后续有上传图片的字段,也没挂起了,没能输出来啊
遇到同样的问题,实际项目中肯定会存在文件和其它表单同时提交的场景的,而且文件上传往往也不是必须的,所以解决方法是暂时不要使用 egg 提供的 getFileStream就好
因为看了下 getFileStream 实现的 代码,
在最开头就判断了是否有文件上传,没有就直接抛出异常,不太友好
async getFileStream() {
const parts = this.multipart({ autoFields: true });
const stream = await parts();
// stream not exists, treat as an exception
// 在最开头就判断了 是否有文件上传
if (!stream || !stream.filename) {
this.throw(400, 'Can\'t found upload file');
}
stream.fields = parts.field;
stream.once('limit', () => {
const err = new Error('Request file too large');
err.name = 'MultipartFileTooLargeError';
err.status = 413;
err.fields = stream.fields;
err.filename = stream.filename;
if (stream.listenerCount('error') > 0) {
stream.emit('error', err);
this.coreLogger.warn(err);
} else {
this.coreLogger.error(err);
// ignore next error event
stream.on('error', () => {});
}
// ignore all data
stream.resume();
});
return stream;
},
所以实现一个类似的方法自己用就好(其实就是去掉那行是否有文件的判断)
// app/extend/context.js
module.exports = {
async getFileStreamWithoutFileNotFoundError() {
const parts = this.multipart({ autoFields: true });
const stream = await parts();
stream.fields = parts.field;
stream.once('limit', () => {
const err = new Error('Request file too large');
err.name = 'MultipartFileTooLargeError';
err.status = 413;
err.fields = stream.fields;
err.filename = stream.filename;
if (stream.listenerCount('error') > 0) {
stream.emit('error', err);
this.coreLogger.warn(err);
} else {
this.coreLogger.error(err);
// ignore next error event
stream.on('error', () => {});
}
// ignore all data
stream.resume();
});
return stream;
}
}
然后在 controller 中使用
class SignUpController extends Controller {
async submit() {
const ctx = this.ctx;
// 这样就算没有文件也不会报错,而且还能获得其它表单的值
const stream = await ctx.getFileStreamWithoutFileNotFoundError();
const { fileds } = stream;
// ...
}
}
@WeiGrand 我们来验证一下。
@WeiGrand https://github.com/eggjs/egg-multipart/pull/17 增加一个函数来更好解决此问题。
guide docs 也可以更新下
@chinalinbo tnpm update 后再看看,另外看你的 begg 对应的 egg 版本。 内部问题,在内网 issue 和钉群讨论。
ctx.getFileStream({ requireFile: false }): 文件非必须
Most helpful comment
@WeiGrand https://github.com/eggjs/egg-multipart/pull/17 增加一个函数来更好解决此问题。