【问题标题】:Angularjs $http post file and form dataAngularjs $http 发布文件和表单数据
【发布时间】:2013-05-10 13:51:08
【问题描述】:

我在 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
});

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    当我不得不同时上传文件和发送用户令牌信息时,我遇到了类似的问题。 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 />
    

    【讨论】:

    • 我同意这应该是公认的答案,因为它允许您在可能需要令牌的地方使用自己的 API
    • 作为一个魅力。当只是复制/粘贴工作时,我是如何喜欢的。伙计,节省了大量时间。
    • 设置后删除Content-Type 是为了确保在转换文件时它是表单数据,然后(在准备好进行发布请求之后)它是@987654328 的正常请求@
    • 咬牙切齿之后,我得到了这个工作(至少在 chrome 48 和 Angular 1.5.0 中使用带有 HttpContext.Request.Files 的 .Net 服务器端)。你不必设置标头到 multipart/form-data,XMLHttpRequest 在幕后为您完成。设置它实际上会弄乱上传。使用'Content-Type': undefined 你也不必删除标题。这让我可以通过 .Net HttpContext.Request.Files API 调用来获取文件服务器端
    • 这几乎可以工作... transformRequest: angular.identity 是你所需要的。您已经在 data 参数中设置了数据。设置标题:{ 'Content-Type': undefined } 就完成了。 Angular 负责将边界正确地附加到内容类型。
    【解决方案2】:

    当发布到 Web.Api 应用程序时,我无法让 Pavel 的答案正常工作。

    问题似乎与删除标题有关。

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

    为了确保允许浏览器默认 Content-Type 和边界参数,我需要将 Content-Type 设置为未定义。使用 Pavel 的示例,从未设置边界,从而导致 400 HTTP 异常。

    关键是删除上面显示的删除标头的代码,并手动将标头内容类型设置为 null。从而允许浏览器设置属性。

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

    【讨论】:

      【解决方案3】:

      我最近写了一个支持原生多文件上传的指令。我创建的解决方案依赖于一项服务来填补您在 $http 服务中发现的空白。我还包含了一个指令,它为您的 Angular 模块提供了一个简单的 API,用于发布文件和数据。

      示例用法:

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

      您可以找到code on github,以及my blog 上的文档

      您可以在 Web 框架中处理文件,但我创建的解决方案提供了将数据传输到服务器的角度接口。您需要编写的角度代码是响应上传事件

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

      【讨论】:

      • 这看起来是相关的和一些体面的信息,但你能不能解释一下,特别是把它与 bsr 的代码联系起来,以及你的代码如何解决他们的问题?
      【解决方案4】:

      请看一下我的实现。您可以将以下函数包装到服务中:

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

      【讨论】:

        【解决方案5】:

        您也可以使用 HTML5 上传。你可以使用这个AJAX uploader

        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()">
        

        【讨论】:

          【解决方案6】:

          这是我的解决方案:

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

            您可以查看http://ngmodules.org/modules/ngUpload 的其他解决方案,如此处所述file uploader integration for angularjs

            【讨论】:

            • 虽然考虑这些选项是明智的,但事实并非如此,还有其他方法可以做到这一点。请参阅 Foo L 的答案或 Pavel Netesa 的
            【解决方案8】:

            在我的解决方案中,我有

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

            }

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-12-03
              • 2017-01-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-11-10
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多