Загрузка файла через FormData

1

Я пытаюсь загрузить файл в бэкэнд узла, который использует Multer. Мултер требует, чтобы форма была представлена определенным образом. Если он не отправлен таким образом, параметр request.file не будет undefined. Я создал подход, который работает с использованием грубой силы. Этот рабочий подход выглядит так:

Индекс-1.html:

<form method="POST" enctype="multipart/form-data" id="fileUploadForm">
  <input type="file" id="selectedFile" name="selectedFile" /><br/><br/>
  <input type="submit" value="Submit" id="btnSubmit"/>
</form>
...
var btn = document.getElementById('btnSubmit');
btn.addEventListener('click', function(e) {
  e.preventDefault();

  var form = $('#fileUploadForm')[0];
  var data = new FormData(form);
  console.log(data);

  $.ajax({
    type: "POST",
    enctype: 'multipart/form-data',
    url: "/upload",
    data: data,
    processData: false,
    contentType: false,
    cache: false,
    timeout: 600000,
    success: function (data) {
      console.log("SUCCESS!");
    },
    error: function (e) {
      console.log("ERROR : ", e);
    }
  });
});        

Код выше успешно отправляет файл на мой сервер. Этот сервер имеет следующее:

server.js

app.post('/upload', upload.single('selectedFile'), function(req, res) {
  if (req.file) {
    console.log('file uploaded');
  } else {
    console.log('no file');
  }

  res.send({});
});

Используя приведенный выше код, "файл загружен" отображается в окне консоли, как ожидалось. Однако мне нужен более динамичный подход. По этой причине мне нужно программно построить форму в JavaScript. В попытке сделать это я создал следующее:

index-2.html [мой пользовательский интерфейс]

var btn = document.getElementById('btnSubmit');
btn.addEventListener('click', function(e) {
  var form = document.createElement('form');
  form.action = '/upload';
  form.method = 'POST';
  form.enctype = 'multipart/form-data';

  var node = document.createElement("input");                        
  node.name = 'selectedFile';
  node.value = GLOBAL_SELECTED_FILE;
  form.appendChild(node);

  var data = new FormData(form);
  data.append('id', this.id);
  console.log(data);

  $.ajax({
    type: 'POST',
    url: '/profile-picture/upload',
    enctype: 'multipart/form-data',                          
    data: data,                            
    contentType: false,
    processData: false,
    success: function(res) {
      console.log('success!');
    },
    error: function(xhr, status, err) {
      console.log('error');
    }
  });
});

Этот второй подход не работает. Чтобы уточнить, переменная GLOBAL_SELECTED_FILE - это данные файла, выбранного из элемента ввода. Данные загружаются через FileReader api. Это выглядит так:

var GLOBAL_SELECTED_FILE = null;

var fileReader = new FileReader();      
fileReader.onload = function(e) {
  GLOBAL_SELECTED_FILE = e.target.result;
}
fileReader.readAsDataURL(fileSelected);  // file selected comes from the onchange event on a <input type="file">..</input> element

В основном, я загружаю предварительный просмотр изображения. В любом случае, когда я нажимаю кнопку отправки в рабочей версии (index-1.html), я замечаю в Fiddler, что другое значение передается по значению, отправленному в index-2.html.

С помощью подхода в index-1.html Fiddler показывает что-то подобное на вкладке "TextView":

------WebKitFormBoundary183mBxXxf1HoE4Et
Content-Disposition: form-data; name="selectedFile"; filename="picture.PNG"
Content-Type: image/png

 PNG

Однако, когда я смотрю на вкладке "TextView" в Fiddler для данных, отправленных через index-2.html, я вижу следующее:

------WebKitFormBoundary9UHBP02of1OI5Zb6
Content-Disposition: form-data; name="selectedFile"

data:image/png;base64,iVBORw0KGg[A LOT MORE TO GO]

Он, как и FormData, использует два разных кодировки для одного и того же значения. Но я не понимаю, почему. Как получить индекс-2.html для отправки изображения в том же формате, что и index-1.html, чтобы Multer заполнил свойство req.file?

Спасибо!

Теги:
multer

1 ответ

0
Лучший ответ

В index-1.html вы используете ввод файла:

<input type="file" id="selectedFile" name="selectedFile" />

В index-2.html вы создаете обычный ввод формы (а не ввод файла):

var node = document.createElement("input");                        
node.name = 'selectedFile';
node.value = GLOBAL_SELECTED_FILE;
form.appendChild(node);

Чтобы создать ввод файла, вам нужно будет добавить node.type = 'file'. Однако вы не сможете установить значение, потому что ограничения безопасности браузера не позволяют установить значение входных файлов.

Вместо этого вам нужно добавить файл, который был выбран пользователем для объекта FormData:

var data = new FormData(form);
data.append('id', this.id);
data.append('selectedFile', $('#fileInputElement')[0].files[0]);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню