Node Multer意外字段

225

我正在使用multer npm模块上传文件到我的应用程序。

我定义的multer函数允许将单个文件上传到文件系统。运行时一切都正常,问题在于上传文件后会出现下面的错误。欢迎就查找位置提供建议。

Error:

Unexpected field

Error: Unexpected field
    at makeError (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\lib\make-error.js:12:13)
    at wrappedFileFilter (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\index.js:39:19)
    at Busboy.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\lib\make-middleware.js:97:7)
    at Busboy.emit (events.js:118:17)
    at Busboy.emit (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\lib\main.js:31:35)
    at PartStream.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\lib\types\multipart.js:205:13)
    at PartStream.emit (events.js:107:17)
    at HeaderParser.<anonymous> (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\Dicer.js:51:16)
    at HeaderParser.emit (events.js:107:17)
    at HeaderParser._finish (c:\Users\Dev\WebstormProjects\Crunch\node_modules\multer\node_modules\busboy\node_modules\dicer\lib\HeaderParser.js:70:8) 

应用程序.js

var multer = require('multer');
var app = express();
var fs = require('fs');

//. . . 

var upload = multer({ dest: 'upload/'});
var type = upload.single('file');

app.post('/upload', type, function (req,res) {
  var tmp_path = req.files.recfile.path;
  var target_path = 'uploads/' + req.files.recfile.name;
fs.readFile(tmp_path, function(err, data)
{
  fs.writeFile(target_path, data, function (err)
  {
    res.render('complete');
  })
});

Index.hbs

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name='recfile' placeholder="Select file"/>
    <br/>
    <button>Upload</button>
</form>

#Package.json
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "easy-zip": "0.0.4",
    "express": "~4.13.1",
    "hbs": "~3.1.0",
    "less-middleware": "1.0.x",
    "morgan": "~1.6.1",
    "multer": "~1.0.0",
    "serve-favicon": "~2.3.0"
  }
}
15个回答

338
在 multer 的 upload.single(<NAME>) 函数中使用的名称 <NAME> 必须与你在 <input type="file" name="<NAME>" ...> 中使用的名称相同。

因此,你需要将

var type = upload.single('file')

更改为

var type = upload.single('recfile')

在你的 app.js 文件中。


14
最好将这个信息放在自述文件里,而不是用“avatar”来填充它。 - hugos
2
但是我们仍然需要在误用的情况下避免异常。如何捕获这个异常? - syberkitten
1
仅供参考,如果您正在使用curl,并且命令看起来像这样:curl -v -F upload=@/myfile.txt http://localhost:3000/upload,那么upload.single的值为“upload”。 - chrismarx
你是对的兄弟。 - Rajib
@Vincent,我们有什么方法可以将错误消息传递给客户端,告诉他们提供的字段名称与上传.single('field name')中指定的不同吗? - Kashif Ali

203
我们必须确保具有名称属性的type=file与传递给upload.single('attr')的参数名称相同。
var multer  = require('multer');
var upload = multer({ dest: 'upload/'});
var fs = require('fs');

/** Permissible loading a single file, 
    the value of the attribute "name" in the form of "recfile". **/
var type = upload.single('recfile');

app.post('/upload', type, function (req,res) {

  /** When using the "single"
      data come in "req.file" regardless of the attribute "name". **/
  var tmp_path = req.file.path;

  /** The original name of the uploaded file
      stored in the variable "originalname". **/
  var target_path = 'uploads/' + req.file.originalname;

  /** A better way to copy the uploaded file. **/
  var src = fs.createReadStream(tmp_path);
  var dest = fs.createWriteStream(target_path);
  src.pipe(dest);
  src.on('end', function() { res.render('complete'); });
  src.on('error', function(err) { res.render('error'); });

});

97
您介意解释一下为什么这个方法有效以及有何不同之处吗? —_____— - IIllIIll
8
完美地运作,就像魔法一样。我们必须确保type=file和name属性与传递给upload.single('attr')的参数名相同。 - Ramki
1
我的情况不起作用。我遇到了同样的问题。但在我的Windows机器上,代码可以工作。我在我的MAC上遇到了问题。有人能帮我吗? - HaRdik Kaji
7
在HTML中,type="file"的name属性应与服务器代码中的upload.single('name')相匹配。 - Prasanth Jaya
如何设置客户端请求以进行多文件上传?“files”字段为空。 - 吳強福
显示剩余7条评论

49

对Vincent答案的跟进。

虽然问题是使用表单,但这并不是直接回答问题。

对我来说,重要的不是使用的输入标签的名称,而是在将文件附加到formData时使用的名称。

前端文件

   var formData = new FormData();
   formData.append('<NAME>',this.new_attachments)

网络服务文件:

   app.post('/upload', upload.single('<NAME>'),...

2
这个救了我的一天。谢谢。 如果您使用FormData.append(),<input>标签的name属性将被覆盖,从而使其他解决方案无法工作。 - Schmidko
1
这个答案非常重要,而且非常有帮助。确保 formData 键名与 upload 键参数相同非常关键。现在它对我起作用了。 - Modermo
1
这很有帮助。 - Ciprianis
1
节省了很多调试时间。上帝保佑你。 - Viraj Singh
1
非常感谢。它帮了我很多,救了我的一天。 - Nika Nabakhteveli
对于任何使用React或Next.js以及像axios或fetch这样的HttpClient的人来说,这是你要寻找的答案。 - kylejw2

7

使用传递文件时所使用的键来代替 input 的 name 属性。

例如:我的 FormData 对象:

客户端代码:

formData.append('file', fileBlob);

服务器端:

multer.single('file');

6
这是你可以使用的API。
 const express        = require('express');
 const bodyParser     = require('body-parser');
 const app = express();
 var multer = require('multer');
 const port = 8000;
 app.use(bodyParser.json());
 app.use(bodyParser.urlencoded({ extended: true }));

 app.listen(port, ()=>{
 console.log('We are live on' + port);
 });

 var upload = multer({dest:'./upload/'});

 app.post('/post', upload.single('file'), function(req, res) {
  console.log(req.file);
 res.send("file saved on server");
 });

这在Postman上也可以正常工作,但是该文件没有.jpg扩展名,有什么建议吗?
如下所述,这是multer的默认功能,如果上传的文件没有扩展名,它会提供文件对象,您可以使用该对象更新文件的扩展名。
var filename = req.file.filename; 
var mimetype = req.file.mimetype; 
mimetype = mimetype.split("/"); 
var filetype = mimetype[1]; 
var old_file = configUploading.settings.rootPathTmp+filename; 
var new_file = configUploading.settings.rootPathTmp+filename+'.'+filetype; 
rname(old_file,new_file);

5

因为有两张图片正在上传!一张带有文件扩展名,另一张没有。

要删除tmp_path(没有扩展名的文件)

src.pipe(dest);之后

添加下面的代码

fs.unlink(tmp_path); //删除tmp_path


4

2022-2023答案

在使用FormData并处理数组时,multer变量名必须包含'[]',而以前不需要。

旧代码:

const multerConfig = upload.fields([
    {name: 'photos', maxCount: 20}
])

2022+ 代码:

const multerConfig = upload.fields([
    {name: 'photos[]', maxCount: 20}
])

1
谢谢您的回答!我正在使用upload.array(),应用相同的更改解决了我的问题。 - jaseeey
我不明白,我已经删除了'[]'部分。然后它对我起作用了。加上'[]'没有任何区别。 - undefined

4

<input type="file" name='recfile' placeholder="Select file"/> 中,文件名被命名为 "recfile" ,而在接收端则使用 "file" 。

解决方案:确保发送和接收的文件名相同,即使用 upload.single('recfile')


3
很不幸,错误信息没有提供清晰的关于实际问题的信息。 因此需要进行一些调试。
从堆栈跟踪中,这是错误在“multer”包中的起源:
function wrappedFileFilter (req, file, cb) {
  if ((filesLeft[file.fieldname] || 0) <= 0) {
    return cb(makeError('LIMIT_UNEXPECTED_FILE', file.fieldname))
  }

  filesLeft[file.fieldname] -= 1
  fileFilter(req, file, cb)
}

这里应用的奇怪(可能错误的)翻译是消息本身的来源...
'LIMIT_UNEXPECTED_FILE': 'Unexpected field'
filesLeft是一个包含服务器期望的字段名的对象,而file.fieldname则包含客户端提供的字段名。当客户端提供的字段名与服务器期望的字段名不匹配时,就会抛出错误。
解决方法是在客户端或服务器上更改名称,以使二者一致。
例如,在客户端使用fetch时...
var theinput = document.getElementById('myfileinput')
var data = new FormData()
data.append('myfile',theinput.files[0])
fetch( "/upload", { method:"POST", body:data } )

服务器将拥有以下路由...
app.post('/upload', multer(multerConfig).single('myfile'),function(req, res){
  res.sendStatus(200)
}

请注意,在本示例中,myfile是通用名称。

非常感谢您的评论,它给了我关于我的错误的提示。在我的情况下,我有两个表单在不同的视图和不同的路由文件中。第一个路由器使用名称字段与视图一并使用,其文件名为“imgLoading”。第二个视图具有另一个名称的文件输入。由于某种原因,multer不允许您在不同的视图中设置不同的名称,因此我决定在两个视图中使用相同的文件输入名称。 - Luis Armando

2

我通过查找我在请求中传递的名称来解决这个问题

我正在发送请求主体:

{thumbbail: <myimg>}

而我期望能够:

upload.single('thumbnail')

所以,我修复了请求中发送的名称


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接