Загрузка файла с помощью POST-запроса в узле.js


у меня проблема с загрузкой файла с помощью запроса POST в узле.js. Я должен использовать request модуль для этого (без внешних НПМ). Сервер должен быть составным запросом с file поле, содержащее данные файла. То, что кажется легким, довольно сложно сделать в узле.js без использования какого-либо внешнего модуля.

Я пробовал использовать но без успеха:

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

4 ответа:

похоже, вы уже используете request модуль.

в этом случае все, что вам нужно после multipart/form-data - это form характеристика:

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

но если вы хотите опубликовать какой-то существующий файл из вашей файловой системы, то вы можете просто передать его как читаемый поток:

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

request будет извлекать все связанные метаданные самостоятельно.

для получения дополнительной информации о размещении multipart/form-data посмотреть node-form-data модуль, который внутренне используется request.

недокументированная особенность

ответ Леонида Бесчастного работает, но мне также пришлось преобразовать ArrayBuffer в буфер, который используется в узле request модуль. После загрузки файла на сервер у меня был он в том же формате, что и HTML5 FileAPI (я использую Meteor). Полный код ниже-может быть, это будет полезно для других.

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

вы также можете использовать поддержку "пользовательские параметры" из библиотеки запросов. Этот формат позволяет создать загрузку нескольких частей формы, но с комбинированной записью как для файла, так и для дополнительной информации о форме, такой как имя файла или тип содержимого. Я обнаружил, что некоторые библиотеки ожидают получить загрузку файлов с использованием этого формата, в частности библиотеки, такие как multer.

этот подход официально задокументирован в разделе формы документа запроса - 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);
    }
  });