【问题标题】:How to POST binary files with AngularJS (with upload DEMO)如何使用 AngularJS 发布二进制文件(带上传演示)
【发布时间】:2019-09-21 05:47:12
【问题描述】:

无法使用 angular post call 发送文件

我正在尝试通过 ionic 1 和 angular 1 发布带有一些数据的 .mp4 文件。通过 POSTMAN 发布时它很好并且可以工作。我在我的应用程序中收到了Success = false

在 POSTMAN 中,下面没有标题和数据, 带有 POST 请求的服务 url http://services.example.com/upload.php 表单数据中的正文

j_id = 4124, type = text   
q_id = 6, type = text   
u_id = 159931, type = text 
file = demo.mp4, type = file

在我的应用中:

$rootScope.uploadQuestion = function () {

    var form = new FormData();
    form.append("j_id", "4124");
    form.append("q_id", "6");
    form.append("u_id", "159931");
    form.append("file", $rootScope.videoAns.name); //this returns media object which contain all details of recorded video

    return $http({
        method: 'POST',
        headers: { 'Content-Type': 'multipart/form-data' }, // also tried with application/x-www-form-urlencoded
        url: 'http://services.example.com/upload.php',
        // url: 'http://services.example.com/upload.php?j_id=4124&q_id=8&u_id=159931&file='+$rootScope.videoAns.fullPath,
        // data: "j_id=" + encodeURIComponent(4124) + "&q_id=" + encodeURIComponent(8) + "&u_id=" + encodeURIComponent(159931) +"&file=" + encodeURIComponent($rootScope.videoAns), 
        data: form,
        cache: false,
        timeout: 300000
    }).success(function (data, status, headers, config) {
        if (status == '200') {
            if (data.success == "true") {
                alert('uploading...');
            }


        }


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

    });
}

【问题讨论】:

标签: angularjs angular-http angularjs-fileupload


【解决方案1】:

推荐:直接发布二进制文件

使用multi-part/form-data 发布二进制文件效率低下,因为base64 encoding 增加了33% 的额外开销。如果服务器 API 接受带有二进制数据的 POST,则直接发布文件:

function upload(url, file) {
    if (file.constructor.name != "File") {
       throw new Error("Not a file");
    }
    var config = {
        headers: {'Content-Type': undefined},
        transformRequest: []
    };
    return $http.post(url, file, config)
      .then(function (response) {
        console.log("success!");
        return response;
    }).catch(function (errorResponse) {
        console.error("error!");
        throw errorResponse;
    });
}

通常$http service 将 JavaScript 对象编码为JSON strings。使用transformRequest: [] 覆盖默认转换。


DEMO of Direct POST

angular.module("app",[])
.directive("selectNgFiles", function() {
  return {
    require: "ngModel",
    link: postLink
  };
  function postLink(scope, elem, attrs, ngModel) {
    elem.on("change", function(event) {
      ngModel.$setViewValue(elem[0].files);
    });
  }
})
.controller("ctrl", function($scope, $http) {
  var url = "//httpbin.org/post";
  var config = {
    headers: { 'Content-type': undefined }
  };
  $scope.upload = function(files) {
    var promise = $http.post(url,files[0],config);
    promise.then(function(response){
      $scope.result="Success "+response.status;
    }).catch(function(errorResponse) {
      $scope.result="Error "+errorRespone.status;
    });
  };
})
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app" ng-controller="ctrl">
    <input type="file" select-ng-files ng-model="files">
    <br>
    <button ng-disabled="!files" ng-click="upload(files)">
      Upload file
    </button>
    <pre>
    Name={{files[0].name}}
    Type={{files[0].type}}
    RESULT={{result}}
    </pre>
  </body>

发帖'Content-Type': 'multipart/form-data'

使用FormData API发布数据时,将内容类型设置为undefined很重要:

function uploadQuestion(file) {

    var form = new FormData();
    form.append("j_id", "4124");
    form.append("q_id", "6");
    form.append("u_id", "159931");
    form.append("file", file); //this returns media object which contain all details of recorded video

    return $http({
        method: 'POST',
        headers: { 'Content-Type': undefined ̶'̶m̶u̶l̶t̶i̶p̶a̶r̶t̶/̶f̶o̶r̶m̶-̶d̶a̶t̶a̶'̶ }, // also tried with application/x-www-form-urlencoded
        url: 'http://services.example.com/upload.php',
        data: form,
        ̶c̶a̶c̶h̶e̶:̶ ̶f̶a̶l̶s̶e̶,̶ 
        timeout: 300000
    ̶}̶)̶.̶s̶u̶c̶c̶e̶s̶s̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
    }).then(function(response) {
        var data = response.data;
        var status = response.status;
        if (status == '200') {
           console.log("Success");
        }    
    ̶}̶)̶.̶e̶r̶r̶o̶r̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
    }).catch(function(response) {
        console.log("ERROR");
        //IMPORTANT
        throw response;    
    });
}

XHR API send method 发送FormData Object 时,它会自动将内容类型标头设置为适当的边界。当$http service覆盖内容类型时,服务器会得到一个没有正确边界的内容类型头。

【讨论】:

  • 我得到了成功的响应,但我仍然无法在该位置发布文件。我收到了app/video/video 的回复,但是我应该收到这个回复app/video/video.mp4
  • 我已经使用了未定义的内容类型,并且我现在得到了高于响应
  • @Mangrio 答案中的代码是正确的。您的问题来自服务器代码或获取file 对象的代码,问题中都不包含这两者。
  • 如何获取文件进度%?
猜你喜欢
  • 2018-10-13
  • 2012-11-08
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多