简体   繁体   English

Angularjs $ http发布文件和表单数据

[英]Angularjs $http post file and form data

I have the below request in python 我在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)

which send a file, and form fields to the backend. 它将文件和表单字段发送到后端。 How can I do the same (sending file + form fields) with Angular $http. 如何使用Angular $ http执行相同的操作(发送文件+表单字段)。 Currently, I do like this, but not sure how to send the file too. 目前,我喜欢这个,但不知道如何发送文件。

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

I had similar problem when had to upload file and send user token info at the same time. 当必须上传文件并同时发送用户令牌信息时,我遇到了类似的问题。 transformRequest along with forming FormData helped: 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) {

        });

For getting file $scope.file I used custom directive: 为了获取文件$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: HTML:

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

I was unable to get Pavel's answer working as in when posting to a Web.Api application. 在发布到Web.Api应用程序时,我无法让Pavel的答案正常工作。

The issue appears to be with the deleting of the headers. 问题似乎是删除标题。

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

In order to ensure the browsers was allowed to default the Content-Type along with the boundary parameter, I needed to set the Content-Type to undefined. 为了确保允许浏览器将Content-Type与边界参数一起默认,我需要将Content-Type设置为undefined。 Using Pavel's example the boundary was never being set resulting in a 400 HTTP exception. 使用Pavel的示例,从未设置边界,从而导致400 HTTP异常。

The key was to remove the code deleting the headers shown above and to set the headers content type to null manually. 关键是删除删除上面显示的标题的代码,并手动将标题内容类型设置为null。 Thus allowing the browser to set the properties. 从而允许浏览器设置属性。

headers: {'Content-Type': undefined}

Here is a full example. 这是一个完整的例子。

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

I recently wrote a directive that supports native multiple file uploads. 我最近写了一个支持本机多文件上传的指令。 The solution I've created relies on a service to fill the gap you've identified with the $http service. 我创建的解决方案依赖于服务来填补您使用$ http服务识别的差距。 I've also included a directive, which provides an easy API for your angular module to use to post the files and data. 我还添加了一个指令,它为角度模块提供了一个简单的API,用于发布文件和数据。

Example usage: 用法示例:

<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)'/>

You can find the code on github , and the documentation on my blog 你可以在github上找到代码 ,在我的博客 找到文档

It would be up to you to process the files in your web framework, but the solution I've created provides the angular interface to getting the data to your server. 您可以自行处理Web框架中的文件,但我创建的解决方案提供了将数据提供给服务器的角度接口。 The angular code you need to write is to respond to the upload events 您需要编写的角度代码是响应上传事件

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

    });

You can also upload using HTML5. 您也可以使用HTML5上传。 You can use this AJAX uploader . 您可以使用此AJAX上传器

The JS code is basically: JS代码基本上是:

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

Which reads from an HTML input element 哪个从HTML输入元素读取

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

here is my solution: 这是我的解决方案:

 // 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> 

Please, have a look on my implementation. 请看看我的实施情况。 You can wrap the following function into a service: 您可以将以下函数包装到服务中:

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

  fd.append('file', file);

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

Please notice, that file argument is a Blob . 请注意,该file参数是Blob If you have base64 version of a file - it can be easily changed to Blob like so: 如果你有一个文件的base64版本 - 它可以像这样轻松更改为Blob

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

您可以在http://ngmodules.org/modules/ngUpload中查看其他解决方案,如此处讨论的angularjs文件上传器集成

In my solution, i have 在我的解决方案中,我有

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

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM