web-dev-qa-db-fra.com

Téléchargement de fichier à l'aide de POST request dans Node.js

J'ai des problèmes pour télécharger le fichier avec la demande POST dans Node.js. Je dois utiliser le module request pour accomplir cela (pas de npms externe). Le serveur doit en faire une demande en plusieurs parties avec le champ file contenant les données du fichier. Ce qui semble être facile est assez difficile à faire dans Node.js sans utiliser de module externe.

J'ai essayé d'utiliser cet exemple mais sans succès:

request.post({
  uri: url,
  method: 'POST',
  multipart: [{
    body: '<FILE_DATA>'
  }]
}, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
68
Jagi

On dirait que vous utilisez déjà module request .

dans ce cas, tout ce dont vous avez besoin de poster multipart/form-data consiste à utiliser sa form feature :

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

mais si vous souhaitez publier un fichier existant à partir de votre système de fichiers, vous pouvez simplement le transmettre sous forme de flux lisible:

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

request extraira toutes les métadonnées associées par lui-même.

Pour plus d'informations sur la publication de multipart/form-data voir module node-form-data , utilisé en interne par request.

93
Leonid Beschastny

Une fonctionnalité non documentée du champ formData que request implémente est la possibilité de passer des options au module form-data qu'il utilise:

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

Ceci est utile si vous devez éviter d'appeler requestObj.form() mais devez télécharger un tampon sous forme de fichier. Le module form-data accepte également les options contentType (type MIME) et knownLength.

Ce changement a été ajouté en octobre 2014 (donc 2 mois après que cette question a été posée), il devrait donc être utilisé sans danger maintenant (en 2017+). Cela équivaut à la version v2.46.0 ou supérieure de request.

18
Clavin

La réponse de Leonid Beschastny fonctionne, mais j'ai également dû convertir ArrayBuffer en Buffer utilisé dans le module request du nœud. Après avoir téléchargé le fichier sur le serveur, je l'avais dans le même format que celui de FileAPI HTML5 (j'utilise Meteor). Le code complet ci-dessous - peut-être sera-t-il utile pour les autres.

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
Jagi

Vous pouvez également utiliser le support "options personnalisées" de la bibliothèque de demandes. Ce format vous permet de créer un téléchargement de formulaire en plusieurs parties, mais avec une entrée combinée pour le fichier et les informations de formulaire supplémentaires, telles que le nom de fichier ou le type de contenu. J'ai constaté que certaines bibliothèques s'attendent à recevoir des téléchargements de fichiers utilisant ce format, en particulier des bibliothèques telles que multer.

Cette approche est officiellement documentée dans la section formulaires de la documentation de la demande - 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);
    }
  });
4
Marwen Landoulsi