Przesyłanie pliku za pomocą żądania POST w węźle.js

Mam problem z załadowaniem pliku za pomocą żądania POST w węźle.js. Aby to osiągnąć, muszę użyć modułu request (brak zewnętrznych npm). Serwer musi być żądaniem wieloczęściowym z polem file zawierającym dane Pliku. To, co wydaje się być łatwe, jest dość trudne do zrobienia w Node.js bez użycia zewnętrznego modułu.

Próbowałem użyć tego przykładu ale bez powodzenia:

request.post({
  uri: url,
  method: 'POST',
  multipart: [{
    body: '<FILE_DATA>'
  }]
}, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
Author: Philip Kirkbride, 2014-08-17

4 answers

Wygląda na to, że już używasz request moduł .

W tym przypadku wystarczy, że napiszesz multipart/form-data, aby użyć jego form funkcja :

var req = request.post(url, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
var form = req.form();
form.append('file', '<FILE_DATA>', {
  filename: 'myfile.txt',
  contentType: 'text/plain'
});

Ale jeśli chcesz opublikować jakiś istniejący plik z systemu plików, możesz po prostu przekazać go jako czytelny strumień:

form.append('file', fs.createReadStream(filepath));

request wyodrębni wszystkie powiązane metadane samodzielnie.

Aby uzyskać więcej informacji na temat zamieszczania multipart/form-data Zobacz node-form-data Moduł , który jest wewnętrznie używany przez request.

 79
Author: Leonid Beschastny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-17 00:00:33

Nieudokumentowaną cechą pola formData, które implementuje request jest możliwość przekazywania opcji do modułu form-data, którego używa:

request({
  url: 'http://example.com',
  method: 'POST',
  formData: {
    'regularField': 'someValue',
    'regularFile': someFileStream,
    'customBufferFile': {
      value: fileBufferData,
      options: {
        filename: 'myfile.bin'
      }
    }
  }
}, handleResponse);

Jest to przydatne, jeśli chcesz uniknąć wywołania requestObj.form(), ale musisz przesłać bufor jako plik. Moduł form-data akceptuje również opcje contentType (typ MIME) i knownLength.

Ta zmiana została dodana w październiku 2014 (a więc 2 miesiące po zadaniu tego pytania), więc powinna być bezpieczna w użyciu teraz (w 2017+). To odpowiada wersji v2.46.0 lub powyżej request.

 9
Author: Clavin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-25 18:39:33

Odpowiedź Leonida Beschastnego działa, ale musiałem również przekonwertować ArrayBuffer na bufor, który jest używany w module request węzła. Po załadowaniu pliku na serwer miałem go w tym samym formacie, który pochodzi z pliku HTML5 (używam Meteor). Pełny kod poniżej-może będzie pomocny dla innych.

function toBuffer(ab) {
  var buffer = new Buffer(ab.byteLength);
  var view = new Uint8Array(ab);
  for (var i = 0; i < buffer.length; ++i) {
    buffer[i] = view[i];
  }
  return buffer;
}

var req = request.post(url, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
var form = req.form();
form.append('file', toBuffer(file.data), {
  filename: file.name,
  contentType: file.type
});
 4
Author: Jagi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 13:26:17

Możesz również skorzystać z obsługi opcji niestandardowych z biblioteki zapytań. Format ten umożliwia utworzenie wieloczęściowego przesłania formularza, ale z połączonym wpisem zarówno dla pliku, jak i dodatkowych informacji formularza, takich jak nazwa pliku lub typ zawartości. Odkryłem, że niektóre biblioteki oczekują przesyłania plików za pomocą tego formatu, w szczególności biblioteki takie jak multer.

To podejście jest oficjalnie udokumentowane w sekcji formularze w dokumentacji żądania - https://github.com/request/request#forms

//toUpload is the name of the input file: <input type="file" name="toUpload">

let fileToUpload = req.file;

let formData = {
    toUpload: {
      value: fs.createReadStream(path.join(__dirname, '..', '..','upload', fileToUpload.filename)),
      options: {
        filename: fileToUpload.originalname,
        contentType: fileToUpload.mimeType
      }
    }
  };
let options = {
    url: url,
    method: 'POST',
    formData: formData
  }
request(options, function (err, resp, body) {
    if (err)
      cb(err);

    if (!err && resp.statusCode == 200) {
      cb(null, body);
    }
  });
 2
Author: Marwen Landoulsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-09 22:45:12