Подтвердить что ты не робот

Многостраничный запрос с AngularJS

У меня есть конечная точка API, к которой я должен отправить многостраничный HTTP-запрос, состоящий из двух частей: file (файл файловой системы) и data (объект JSON).

После некоторых исследований я узнал, как сделать многостраничный запрос в AngularJS:

$http({
   method: 'POST',
   url: url,
   headers: {
      'Content-Type': 'multipart/form-data'
   },
   data: {
      data: model,
      file: file
   },
   transformRequest: customFormDataObject
});

1) Функция customFormDataObject первоначально имела следующую форму:

customFormDataObject formDataObject = function (data, headersGetter) {
   var fd = new FormData();
   angular.forEach(data, function (value, key) {
      fd.append(key, value);
   });

   var headers = headersGetter();
   delete headers['Content-Type'];

   return fd;
};

Результат этой реализации состоит в том, что отдельные части запроса не имеют для них contentType.

2). Прочитав еще несколько (qaru.site/info/277357/...), я попытался использовать Blob для этого, объект customFormData выглядит следующим образом (немного беспорядок, в основном первая часть будет contentType application/json, вторая image/png):

customFormDataObject = function (data, headersGetter) {
    var fd = new FormData();

    var contentType = 'application/json';
    angular.forEach(data, function (value, key) {
         fd.append(key, new Blob([JSON.stringify(value)], {
             type: contentType
         }));
         contentType = 'image/png';
    });

    var headers = headersGetter();
    delete headers['Content-Type'];

    return fd;
 };

Этот второй подход устанавливает правильную contentType для каждой части запроса, но не устанавливает значения для частей.

В основном, что происходит с 1), правильные значения задаются в multiparts, но contentType не установлены. С 2) установлены contentType, но не значения для множителей.

Я что-то упустил? Эта функция не должна работать так?

Спасибо!

4b9b3361

Ответ 1

Самый простой способ загрузки файлов в Angular:

var fd = new FormData();
fd.append('file', file);
fd.append('data', 'string');
$http.post(uploadUrl, fd, {
   transformRequest: angular.identity,
   headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});

Абсолютно необходимы следующие два свойства объекта конфигурации:

transformRequest: angular.identity

переопределяет Angular сериализацию по умолчанию, оставляя наши данные неповрежденными.

headers: {'Content-Type': undefined }

позволяет браузеру определить правильный Content-Type как multipart/form-data и заполнить правильную границу.

Ничто другое не сработало для меня! Предоставлено Lady Louthan замечательный блогпост.

Ответ 2

Вы пробовали что-то вроде этого:

$httpProvider.defaults.transformRequest = function(data) {
  if (data === undefined){
    return data;
  }

  var formData = new FormData();
  for (var key in data){
    if(typeof data[key] == 'object' && !(data[key] instanceof File)){
      formData.append(key, JSON.stringify(data[key]));
    }else{
      formData.append(key, data[key]);
    }
  }
  return formData;
};

Ответ 3

Я точно решаю ту же проблему.

После некоторых тестов у меня была такая ситуация, которую вы описали:

В основном, что происходит с 1) правильные значения задаются в multiparts, но contentType не заданы. С 2) задан тип contentType, но не значения для multiparts.

Чтобы устранить эту проблему, мне пришлось использовать Blob и Post Ajax вместо $http Post.

Кажется, что $http работает неправильно в этом случае.

код:

    var formData = new FormData();

    var blobId = new Blob([100], { 'type':'text/plain' });
    formData.append('testId', blobId);

    var blobImage = fileService.base64ToBlob(contentToDecode, 'image/jpeg');
    formData.append('file', blobImage, 'imagem' + (i + 1) + '.jpg');

Запрос:

    $.ajax({
      url: url,
      data: formData,
      cache: false,
      contentType: false,
      processData: false,
      type: 'POST',
      success: function(response) {
        deferred.resolve(response);
        $rootScope.requestInProgress = false;
      },
      error: function(error) {
        deferred.reject(error);
        $rootScope.requestInProgress = false;
      }
    });

Ответ 4

Вы можете использовать https://github.com/danialfarid/ng-file-upload/.

В этом загружаемом файле есть положение для отправки файла и данных (в формате JSON) отдельно, как вы упомянули в своем вопросе выше.

Для Ex: -

var upload = $upload.upload({
                 url: url,
                 file: file,
                 method: 'POST' or 'PUT', default POST,
                 headers: {'Content-Type': 'multipart/form-data'}, // only for html5
                 fileName: 'doc.jpg',
                 fileFormDataName: 'myFile',
                 data: {'data': model}
             });

В приведенном выше коде вы можете отправить запрос POST или PUT с помощью "multipart/form-data", файла и объекта данных как JSON отдельно.

Для получения дополнительной информации вы можете перейти по ссылке выше и посмотреть ReadMe.md плагина.

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

Ответ 5

что я сделал, чтобы решить это.

var formData = new FormData(document.getElementById('myFormId'));

то в моем сервисе

                var deferred = $q.defer();
                $http.post('myurl', formData, {
                    cache: false,
                    contentType: false,
                    processData: false,
                })
                    .success(function (response) {
                        deferred.resolve(response);
                    })
                    .error(function (reject) {
                        deferred.reject(reject);
                    });
                return deferred.promise;