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

Angularjs $http post file и данные формы

У меня есть следующий запрос в python

import requests, json, io

cookie = {}
payload = {"Name":"abc"}
url = "/test"
file = "out/test.json"

fi = {'file': ('file', open(file) )}
r = requests.post("http://192.168.1.1:8080" + url, data=payload, files=fi, cookies=cookie)
print(r.text)

которые отправляют файл и формируют поля на бэкэнд. Как я могу сделать то же самое (отправка файла + поля формы) с помощью Angular $http. В настоящее время мне это нравится, но не знаю, как отправить файл.

var payload = {"Name":"abc"};
$http.post('/test', payload)
    .success(function (res) {
    //success
});
4b9b3361

Ответ 1

Недавно я написал директиву, поддерживающую несколько загрузок файлов. Решение, которое я создал, зависит от службы, чтобы заполнить пробел, который вы идентифицировали с помощью службы $http. Я также включил директиву, которая предоставляет простой API для вашего модуля angular для публикации файлов и данных.

Пример использования:

<lvl-file-upload
    auto-upload='false'
    choose-file-button-text='Choose files'
    upload-file-button-text='Upload files'
    upload-url='http://localhost:3000/files'
    max-files='10'
    max-file-size-mb='5'
    get-additional-data='getData(files)'
    on-done='done(files, data)'
    on-progress='progress(percentDone)'
    on-error='error(files, type, msg)'/>

Вы можете найти код на github, а документацию на my блог

Это зависит от вас, чтобы обрабатывать файлы в вашей веб-среде, но созданное мной решение обеспечивает интерфейс angular для получения данных на ваш сервер. Код angular, который вам нужно написать, - это отвечать на события загрузки

angular
    .module('app', ['lvl.directives.fileupload'])
    .controller('ctl', ['$scope', function($scope) {
        $scope.done = function(files,data} { /*do something when the upload completes*/ };
        $scope.progress = function(percentDone) { /*do something when progress is reported*/ };
        $scope.error = function(file, type, msg) { /*do something if an error occurs*/ };
        $scope.getAdditionalData = function() { /* return additional data to be posted to the server*/ };

    });

Ответ 2

У меня была аналогичная проблема, когда приходилось загружать файл и отправлять данные токена пользователя одновременно. transformRequest вместе с формированием FormData помогли:

        $http({
            method: 'POST',
            url: '/upload-file',
            headers: {
                'Content-Type': 'multipart/form-data'
            },
            data: {
                email: Utils.getUserInfo().email,
                token: Utils.getUserInfo().token,
                upload: $scope.file
            },
            transformRequest: function (data, headersGetter) {
                var formData = new FormData();
                angular.forEach(data, function (value, key) {
                    formData.append(key, value);
                });

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

                return formData;
            }
        })
        .success(function (data) {

        })
        .error(function (data, status) {

        });

Для получения файла $scope.file я использовал настраиваемую директиву:

app.directive('file', function () {
    return {
        scope: {
            file: '='
        },
        link: function (scope, el, attrs) {
            el.bind('change', function (event) {
                var file = event.target.files[0];
                scope.file = file ? file : undefined;
                scope.$apply();
            });
        }
    };
});

Html:

<input type="file" file="file" required />

Ответ 3

Мне не удалось заставить Павла отвечать, как при публикации в приложении Web.Api.

Проблема связана с удалением заголовков.

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

Чтобы браузеру разрешили по умолчанию использовать Content-Type вместе с граничным параметром, мне нужно было установить Content-Type на undefined. Используя пример Павла, граница никогда не была установлена, что привело к исключению 400 HTTP.

Ключ должен был удалить код, удаляющий заголовки, показанные выше, и установить тип содержимого заголовков пустым вручную. Таким образом, браузер может установить свойства.

headers: {'Content-Type': undefined}

Вот полный пример.

$scope.Submit = form => {
                $http({
                    method: 'POST',
                    url: 'api/FileTest',
                    headers: {'Content-Type': undefined},
                    data: {
                        FullName: $scope.FullName,
                        Email: $scope.Email,
                        File1: $scope.file
                    },
                    transformRequest: function (data, headersGetter) {
                        var formData = new FormData();
                        angular.forEach(data, function (value, key) {
                            formData.append(key, value);
                        });
                        return formData;
                    }
                })
                .success(function (data) {

                })
                .error(function (data, status) {

                });

                return false;
            }

Ответ 4

Вы также можете загрузить с помощью HTML5. Вы можете использовать этот загрузчик AJAX.

Код JS в основном:

  $scope.doPhotoUpload = function () {
    // ..
    var myUploader = new uploader(document.getElementById('file_upload_element_id'), options);
    myUploader.send();
    // ..
  }

Что читается из входного элемента HTML

<input id="file_upload_element_id" type="file" onchange="angular.element(this).scope().doPhotoUpload()">

Ответ 5

вот мое решение:

// Controller
$scope.uploadImg = function( files ) {
  $scope.data.avatar = files[0];
}

$scope.update = function() {
  var formData = new FormData();
  formData.append('desc', data.desc);
  formData.append('avatar', data.avatar);
  SomeService.upload( formData );
}


// Service
upload: function( formData ) {
  var deferred = $q.defer();
  var url = "/upload"	;
  
  var request = {
    "url": url,
    "method": "POST",
    "data": formData,
    "headers": {
      'Content-Type' : undefined // important
    }
  };

  console.log(request);

  $http(request).success(function(data){
    deferred.resolve(data);
  }).error(function(error){
    deferred.reject(error);
  });
  return deferred.promise;
}


// backend use express and multer
// a part of the code
var multer = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '../public/img')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now() + '.jpg');
  }
})

var upload = multer({ storage: storage })
app.post('/upload', upload.single('avatar'), function(req, res, next) {
  // do something
  console.log(req.body);
  res.send(req.body);
});
<div>
  <input type="file" accept="image/*" onchange="angular.element( this ).scope().uploadImg( this.files )">
  <textarea ng-model="data.desc" />
  <button type="button" ng-click="update()">Update</button>
</div>

Ответ 7

В моем решении у меня есть

$scope.uploadVideo = function(){
    var uploadUrl = "/api/uploadEvent";


    //obj with data, that can be one input or form
    file = $scope.video;
    var fd = new FormData();


    //check file form on being
    for (var obj in file) {
        if (file[obj] || file[obj] == 0) {
            fd.append(obj, file[obj]);
        }
    }

    //open XHR request
    var xhr = new XMLHttpRequest();


    // $apply to rendering progress bar for any chunking update
    xhr.upload.onprogress = function(event) {
        $scope.uploadStatus = {
            loaded: event.loaded,
            total:  event.total
        };
        $scope.$apply();
    };

    xhr.onload = xhr.onerror = function(e) {
        if (this.status == 200 || this.status == 201) {

            //sucess

            $scope.uploadStatus = {
                loaded: 0,
                total:  0
            };


            //this is for my solution
            $scope.video = {};
            $scope.vm.model.push(JSON.parse(e.currentTarget.response));
            $scope.$apply();

        } else {
           //on else status
        }
    };

    xhr.open("POST", uploadUrl, true);

    //token for upload, thit for my solution
    xhr.setRequestHeader("Authorization", "JWT " + window.localStorage.token);


    //send
    xhr.send(fd); 
};

}

Ответ 8

Пожалуйста, посмотрите мою реализацию. Вы можете обернуть следующую функцию в службу:

function(file, url) {
  var fd = new FormData();

  fd.append('file', file);

  return $http.post(url, fd, {
    transformRequest: angular.identity,
    headers: { 'Content-Type': undefined }
  });
}

Обратите внимание, что аргумент file имеет значение Blob. Если у вас есть версия файла base64 - ее можно легко изменить на Blob следующим образом:

fetch(base64).then(function(response) {
  return response.blob(); 
}).then(console.info).catch(console.error);