Nieoczekiwane pole Node Multera


139

Pracuję nad przesłaniem pliku do mojej aplikacji przy użyciu modułu multer npm.

Funkcja multer, którą zdefiniowałem, polega na zezwalaniu na przesyłanie pojedynczego pliku do systemu plików. Wszystko działa w czasie wykonywania; problem polega na tym, że po przesłaniu pliku pojawia się poniżej błąd. Każda cenna rada, gdzie szukać.

Błąd:

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) 

app.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"
  }
}

Odpowiedzi:


152

Musimy upewnić się, że plik type = z atrybutem nazwy powinien być taki sam, jak przekazana nazwa parametru 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'); });

});

89
Czy mógłbyś wyjaśnić, dlaczego to działa, a co się zmieniło? —_____—
IIllIIll

8
Działa idealnie jak urok. Musimy upewnić się, że typ = plik z atrybutem nazwy jest taki sam, jak nazwa parametru przekazana w upload.single ('attr')
Ramki

1
Mój przypadek nie działa. Mam ten sam problem. Ale w moim Windowsie działa kod maszynowy. Mam problemy z moim adresem MAC.? Czy ktoś może mi w tym pomóc?
HaRdik Kaji

6
Atrybut nazwy typu type = "file" w html powinien być zgodny z upload.single („name”) w kodzie serwera.
Prasanth Jaya,

Jak ustawić żądanie klienta dotyczące przesyłania wielu plików? Pole „pliki” jest puste.
吳 強 福

222

Funkcja, <NAME>której używasz w multer, upload.single(<NAME>)musi być taka sama, jak ta, której używasz w <input type="file" name="<NAME>" ...>.

Więc musisz się zmienić

var type = upload.single('file')

do

var type = upload.single('recfile')

w tobie app.js

Mam nadzieję że to pomoże.


3
Pomogłoby, gdyby umieścili to w pliku readme zamiast wypełniać go „awatarem”.
hugos

1
Ale nadal musimy unikać wyjątku w przypadku nadużycia… jak złapać ten wyjątek?
syberkitten

Dla porównania, jeśli używasz curl, a polecenie wygląda następująco: curl -v -F upload=@/myfile.txt localhost: 3000 / upload Wtedy wartością upload.single jest "upload"
chrismarx

19

Kontynuacja odpowiedzi Vincenta.

Nie jest to bezpośrednia odpowiedź na pytanie, ponieważ pytanie jest przy użyciu formularza.

U mnie nie była to nazwa tagu wejściowego, która została użyta, ale nazwa podczas dołączania pliku do formData.

plik frontendu

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

plik usługi sieciowej:

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

To uratowało mi dzień. Dziękuję Ci. Jeśli używasz FormData.append (), atrybut nazwy ze znacznika <input> zostanie nadpisany i spowoduje, że inne rozwiązania nie będą działać.
Schmidko

1
Ta odpowiedź jest tak ważna i niezwykle pomocna. Upewnienie się, że formDatanazwa klucza jest taka sama jak uploadargument klucza, jest kluczowe. Teraz mi to pasuje.
Modermo

4

ponieważ przesyłane są 2 obrazy! jeden z rozszerzeniem, a drugi bez rozszerzenia. usunąć tmp_path (plik bez rozszerzenia)

po
src.pipe(dest);

dodaj poniższy kod

fs.unlink(tmp_path); //deleting the tmp_path


4

To dla interfejsu API, którego możesz użyć

 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");
 });

Działa to również dobrze w programie Postman, ale plik nie ma rozszerzenia .jpg. Jak skomentowano poniżej

Jest to domyślna funkcja multer, jeśli przesyła plik bez rozszerzenia, zapewnia jednak obiekt pliku, za pomocą którego można zaktualizować rozszerzenie pliku.

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);

1

Niestety, komunikat o błędzie nie zawiera jasnych informacji na temat prawdziwego problemu. W tym celu wymagane jest pewne debugowanie.

Ze śladu stosu, oto źródło błędu w multerpakiecie:

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)
}

A zastosowane tutaj dziwne (być może błędne) tłumaczenie jest źródłem samego przekazu ...

'LIMIT_UNEXPECTED_FILE': 'Unexpected field'

filesLeftto obiekt, który zawiera nazwę pola, którego oczekuje serwer, i file.fieldnamezawiera nazwę pola podanego przez klienta. Błąd jest generowany, gdy występuje niezgodność między nazwą pola podaną przez klienta a nazwą pola oczekiwaną przez serwer.

Rozwiązaniem jest zmiana nazwy na kliencie lub serwerze, tak aby były zgodne.

Na przykład, gdy używasz fetchna kliencie ...

var theinput = document.getElementById('myfileinput')
var data = new FormData()
data.append('myfile',theinput.files[0])
fetch( "/upload", { method:"POST", body:data } )

Serwer miałby taką trasę jak następująca ...

app.post('/upload', multer(multerConfig).single('myfile'),function(req, res){
  res.sendStatus(200)
}

Zwróć uwagę, że jest myfileto nazwa zwyczajowa (w tym przykładzie).


Dziękuję bardzo. Twój komentarz dał mi wskazówkę dotyczącą mojego błędu. W moim przypadku miałem 2 formularze w różnych widokach i różnych plikach routera. Pierwszy router używał pola nazwy z pierwszym widokiem, a jego nazwa pliku to „imgLoading”. Drugi widok miał inną nazwę pliku wejściowego. Z jakiegoś powodu multer nie pozwala na ustawienie różnych nazw w różnych widokach, więc zdecydowałem się użyć tej samej nazwy dla wejścia pliku w obu widokach.
Luis Armando

1

Rozwiązuję ten problem szukając nazwiska, które przekazałem na moją prośbę

Wysyłałem na ciało:

{thumbbail: <myimg>}

i miałem:

upload.single('thumbnail')

więc poprawiam nazwę, którą wysyłam na żądanie


1

Inna nazwa pliku, który został opublikowany jako „ recfile ” pod adresem <input type="file" name='recfile' placeholder="Select file"/>i odebrany jako „ plik ” pod adresem upload.single('file')

Rozwiązanie : upewnij się, że wysłany i odebrany plik są podobneupload.single('recfile')


0

W moim scenariuszu działo się tak, ponieważ zmieniłem nazwę parametru w, swagger.yamlale nie załadowałem ponownie strony z dokumentami.

Dlatego próbowałem API z nieoczekiwanym parametrem wejściowym.
Krótko mówiąc, F5jest moim przyjacielem.


0

prawdopodobnie nie podajesz tej samej nazwy, o której wspomniałeś w upload.single('file').


0

W moim przypadku miałem 2 formularze w różnych widokach i różnych plikach routera. Pierwszy router używał pola nazwy z widokiem pierwszy, a jego nazwa pliku to „inputGroupFile02”. Drugi widok miał inną nazwę do wprowadzania plików. Z jakiegoś powodu Multer nie pozwala na ustawienie różnych nazw w różnych widokach, więc zdecydowałem się użyć tej samej nazwy dla wejścia pliku w obu widokach.

wprowadź opis obrazu tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.