【问题标题】:Send FormData with other field in AngularJS使用AngularJS中的其他字段发送FormData
【发布时间】:2016-05-04 23:34:12
【问题描述】:

我有一个包含两个input text 和一个upload 的表单。我必须将它发送到服务器,但我在将文件与文本连接时遇到了一些问题。服务器期望得到这个答案:

"title=first_input" "text=second_input" "file=my_file.pdf"

这是html

<input type="text" ng-model="title">
<input type="text" ng-model="text">
<input type="file" file-model="myFile"/>
<button ng-click="send()">

这是控制器

$scope.title = null;
$scope.text = null;

$scope.send = function(){
  var file = $scope.myFile;
  var uploadUrl = 'my_url';
  blockUI.start();
  Add.uploadFileToUrl(file, $scope.newPost.title, $scope.newPost.text, uploadUrl);
};

这是指令文件模型:

  return {
restrict: 'A',
link: function(scope, element, attrs) {
  var model = $parse(attrs.fileModel);
  var modelSetter = model.assign;

  element.bind('change', function(){
    scope.$apply(function(){
      modelSetter(scope, element[0].files[0]);
    });
  });
}
};

这是调用服务器的Service

  this.uploadFileToUrl = function(file, title, text, uploadUrl){
   var fd = new FormData();
   fd.append('file', file);
   var obj = {
     title: title,
     text: text,
     file: fd
   };
   var newObj = JSON.stringify(obj);

     $http.post(uploadUrl, newObj, {
       transformRequest: angular.identity,
       headers: {'Content-Type': 'multipart/form-data'}
     })
  .success(function(){
    blockUI.stop();
  })
  .error(function(error){
    toaster.pop('error', 'Errore', error);
  });
}

如果我尝试发送,我会收到错误 400,并且响应是:Multipart form parse error - Invalid boundary in multipart: None。 请求的有效载荷是:{"title":"sadf","text":"sdfsadf","file":{}}

【问题讨论】:

  • 你序列化FormData有什么原因吗?

标签: angularjs http http-post multipartform-data form-data


【解决方案1】:

不要将FormDataPOST 序列化到服务器。这样做:

this.uploadFileToUrl = function(file, title, text, uploadUrl){
    var payload = new FormData();

    payload.append("title", title);
    payload.append('text', text);
    payload.append('file', file);

    return $http({
        url: uploadUrl,
        method: 'POST',
        data: payload,
        //assign content-type as undefined, the browser
        //will assign the correct boundary for us
        headers: { 'Content-Type': undefined},
        //prevents serializing payload.  don't do it.
        transformRequest: angular.identity
    });
}

那就用吧:

MyService.uploadFileToUrl(file, title, text, uploadUrl).then(successCallback).catch(errorCallback);

【讨论】:

  • 问题出在您的后端控制器上。不是 Javascript。
  • 我不管理后端,我会问我的朋友谁做的。附:你写了 fd.append 但我想它们都是 payload.append,对吧?
  • 是的。我的错。有效载荷是 fd
  • 可能因为文件未定义而出错?查看请求有效负载:-----------------185657102119953796721894889690 Content-Disposition: form-data; name="title" tgrfdc -----------------185657102119953796721894889690 内容配置:表单数据; name="text" tgfrds -----------------185657102119953796721894889690 内容配置:表单数据; name="file" 未定义 -----------------------------185657102119953796721894889690--
  • 这是问题所在,服务器要求文件,它不能是未定义的......但我解决了,因为我没有加载包含上传指令的文件...... .LOL 非常感谢你,我使用了你的解决方案。再次感谢
【解决方案2】:

这里是完整的解决方案

html代码,

创建如下所示的文本anf文件上传字段

    <div class="form-group">
        <div>
            <label for="usr">User Name:</label>
            <input type="text" id="usr" ng-model="model.username">
        </div>
        <div>
            <label for="pwd">Password:</label>
            <input type="password" id="pwd" ng-model="model.password">
        </div><hr>
        <div>
            <div class="col-lg-6">
                <input type="file" file-model="model.somefile"/>
            </div>


        </div>
        <div>
            <label for="dob">Dob:</label>
            <input type="date" id="dob" ng-model="model.dob">
        </div>
        <div>
            <label for="email">Email:</label>
            <input type="email"id="email" ng-model="model.email">
        </div>


        <button type="submit" ng-click="saveData(model)" >Submit</button>

指令代码

创建一个文件模型指令来解析文件

.directive('fileModel', ['$parse', function ($parse) {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var model = $parse(attrs.fileModel);
        var modelSetter = model.assign;

        element.bind('change', function(){
            scope.$apply(function(){
                modelSetter(scope, element[0].files[0]);
            });
        });
    }
};}]);

服务代码

附加文件和字段以形成数据并执行 $http.post 如下所示 记得保留 'Content-Type': undefined

 .service('fileUploadService', ['$http', function ($http) {
    this.uploadFileToUrl = function(file, username, password, dob, email, uploadUrl){
        var myFormData = new FormData();

        myFormData.append('file', file);
        myFormData.append('username', username);
        myFormData.append('password', password);
        myFormData.append('dob', dob);
        myFormData.append('email', email);


        $http.post(uploadUrl, myFormData, {
            transformRequest: angular.identity,
            headers: {'Content-Type': undefined}
        })
            .success(function(){

            })
            .error(function(){
            });
    }
}]);

在控制器中

现在在控制器中通过发送需要附加在参数中的数据来调用服务,

$scope.saveData  = function(model){
    var file = model.myFile;
    var uploadUrl = "/api/createUsers";
    fileUpload.uploadFileToUrl(file, model.username, model.password, model.dob, model.email, uploadUrl);
};

【讨论】:

    【解决方案3】:

    您将 JSON 格式的数据发送到不期望该格式的服务器。您已经提供了服务器所需的格式,因此您需要自己格式化,这非常简单。

    var data = '"title='+title+'" "text='+text+'" "file='+file+'"';
    $http.post(uploadUrl, data)
    

    【讨论】:

    • 自从在我的服务中我写过: var data = '"title=' + title +'" "text=' + text + '" "file=' + file +'"'; $http.post(uploadUrl, data, { transformRequest: angular.identity, headers: {'Content-Type': 'multipart/form-data'} }) 并且响应是:“多部分表单解析错误 - 多部分中的边界无效: None".. 事实上,如果我看到负载请求,它是:"title=Aasd" "text=njkopè" "file=undefined" ...为什么?
    • 我稍微更改了代码。现在它使用传递给uploadFileToUrl 函数的参数,该函数将包含“file”参数。试试看。
    • 总是未定义...://
    【解决方案4】:

    这永远行不通,你不能字符串化你的 FormData 对象。

    你应该这样做:

    this.uploadFileToUrl = function(file, title, text, uploadUrl){
       var fd = new FormData();
       fd.append('title', title);
       fd.append('text', text);
       fd.append('file', file);
    
         $http.post(uploadUrl, obj, {
           transformRequest: angular.identity,
           headers: {'Content-Type': undefined}
         })
      .success(function(){
        blockUI.stop();
      })
      .error(function(error){
        toaster.pop('error', 'Errore', error);
      });
    }
    

    【讨论】:

      【解决方案5】:

      在 AngularJS 中使用 $resource 你可以:

      task.service.js

      $ngTask.factory("$taskService", [
          "$resource",
          function ($resource) {
              var taskModelUrl = 'api/task/';
              return {
                  rest: {
                      taskUpload: $resource(taskModelUrl, {
                          id: '@id'
                      }, {
                          save: {
                              method: "POST",
                              isArray: false,
                              headers: {"Content-Type": undefined},
                              transformRequest: angular.identity
                          }
                      })
                  }
              };
          }
      ]);
      

      然后在模块中使用:

      task.module.js

      $ngModelTask.controller("taskController", [
          "$scope",
          "$taskService",
          function (
              $scope,
              $taskService,
          ) {
          $scope.saveTask = function (name, file) {
              var newTask,
                  payload = new FormData();
              payload.append("name", name);
              payload.append("file", file);
              newTask = $taskService.rest.taskUpload.save(payload);
              // check if exists
          }
      }
      

      【讨论】:

        【解决方案6】:

        假设我们想使用 POST 方法从 PHP 服务器获取特定图像的列表。

        您必须在表单中为 POST 方法提供两个参数。以下是您将要执行的操作。

        app.controller('gallery-item', function ($scope, $http) {
        
            var url = 'service.php'; 
        
            var data = new FormData();
        
            data.append("function", 'getImageList');
            data.append('dir', 'all');
        
            $http.post(url, data, {
                transformRequest: angular.identity,
                headers: {'Content-Type': undefined}
              }).then(function (response) {
        
                  // This function handles success
                console.log('angular:', response);
        
            }, function (response) {
        
                // this function handles error
        
            });
        });
        

        我已经在我的系统上对其进行了测试,它可以工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-21
          • 1970-01-01
          • 2011-07-20
          相关资源
          最近更新 更多