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

У меня есть проблема с загрузкой файла с помощью запроса POST в Node.js. Я должен использовать модуль request для выполнения этого (без внешних npms). Серверу требуется, чтобы он был многопрофильным запросом с полем file, содержащим данные файла. Кажется, что это легко сделать в Node.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);
  }
});

Ответ 1

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

в этом случае все, что вам нужно отправить 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 module, который внутренне используется request.

Ответ 2

Недокументированная функция поля formData, реализуемая request, - это возможность передавать параметры в модуль form-data, который использует:

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

Это полезно, если вам нужно избегать вызова requestObj.form(), но нужно загрузить буфер в виде файла. Модуль form-data также принимает contentType (тип MIME) и knownLength.

Это изменение было добавлено в октябре 2014 года (через 2 месяца после того, как этот вопрос был задан), поэтому его следует использовать в безопасном режиме (в 2017+). Это соответствует версии v2.46.0 или выше request.

Ответ 3

Ответ Leonid Beschastny работает, но мне также пришлось преобразовать ArrayBuffer в буфер, который используется в модуле Node 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
});

Ответ 4

вы можете использовать это:

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