使用AngularJS的多部分请求

时间:2015-03-06 16:04:24

标签: angularjs multipartform-data multipart

我有一个API端点,我必须向其发送多部分HTTP请求,由两部分file(文件系统文件)和data(一个JSON对象)组成。

经过一些研究后,我发现了如何在AngularJS中执行多部分请求:

$http({
   method: 'POST',
   url: url,
   headers: {
      'Content-Type': 'multipart/form-data'
   },
   data: {
      data: model,
      file: file
   },
   transformRequest: customFormDataObject
});

1) customFormDataObject函数最初具有以下形式:

customFormDataObject formDataObject = function (data, headersGetter) {
   var fd = new FormData();
   angular.forEach(data, function (value, key) {
      fd.append(key, value);
   });

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

   return fd;
};

此实施的结果是请求的各个部分没有设置contentType

2)在阅读了更多内容(https://stackoverflow.com/a/24535293/689216)后,我尝试使用 Blob customFormData对象看起来像这样(a有点乱,基本上第一部分是contentType application/json,第二部分是image/png):

customFormDataObject = function (data, headersGetter) {
    var fd = new FormData();

    var contentType = 'application/json';
    angular.forEach(data, function (value, key) {
         fd.append(key, new Blob([JSON.stringify(value)], {
             type: contentType
         }));
         contentType = 'image/png';
    });

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

    return fd;
 };

第二种方法为请求的每个部分设置了正确的contentType,但它没有为部分设置任何值。

基本上发生的是 1)在多部分中设置了正确的值,但未设置contentType。使用 2)设置contentType,但不设置多部分的值。

我错过了什么吗?这个功能不应该像这样工作吗?

谢谢!

5 个答案:

答案 0 :(得分:29)

在Angular中上传文件的最简单方法:

var fd = new FormData();
fd.append('file', file);
fd.append('data', 'string');
$http.post(uploadUrl, fd, {
   transformRequest: angular.identity,
   headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});

绝对必要的是配置对象的以下两个属性:

transformRequest: angular.identity

覆盖Angular的默认序列化,保留我们的数据。

headers: {'Content-Type': undefined }

让浏览器检测到正确的Content-Typemultipart/form-data,并填写正确的边界。

没有其他任何对我有用!感谢Lady Louthan的wonderful blogpost

答案 1 :(得分:4)

你有没有试过这样的事情:

$httpProvider.defaults.transformRequest = function(data) {
  if (data === undefined){
    return data;
  }

  var formData = new FormData();
  for (var key in data){
    if(typeof data[key] == 'object' && !(data[key] instanceof File)){
      formData.append(key, JSON.stringify(data[key]));
    }else{
      formData.append(key, data[key]);
    }
  }
  return formData;
};

答案 2 :(得分:4)

我只是解决了同样的问题。

经过一些测试后,我遇到了你所描述的情况:

基本上发生的事情是1)在multiparts中设置了正确的值,但是没有设置contentType。 2)设置了contentType,但不设置multiparts的值。

要解决此问题,我必须使用Blob和发布Ajax 而不是 $ http Post

在这种情况下,似乎$ http无法正常工作。

代码:

slideUp()

请求:

    var formData = new FormData();

    var blobId = new Blob([100], { 'type':'text/plain' });
    formData.append('testId', blobId);

    var blobImage = fileService.base64ToBlob(contentToDecode, 'image/jpeg');
    formData.append('file', blobImage, 'imagem' + (i + 1) + '.jpg');

答案 3 :(得分:2)

您可以使用https://github.com/danialfarid/ng-file-upload/

在此文件上传器中,如上所述,您可以单独发送文件和数据(采用JSON格式)。

对于Ex: -

var upload = $upload.upload({
                 url: url,
                 file: file,
                 method: 'POST' or 'PUT', default POST,
                 headers: {'Content-Type': 'multipart/form-data'}, // only for html5
                 fileName: 'doc.jpg',
                 fileFormDataName: 'myFile',
                 data: {'data': model}
             });

在上面的代码中,您可以单独发送一个POST或PUT请求,其中包含多部分/表格数据',文件和数据对象作为JSON。

有关详细信息,请访问以上链接并查看插件的ReadMe.md。

我知道我的方法与您目前正在遵循的方法略有不同,但目标是相同的。

答案 4 :(得分:0)

我为解决这个问题做了什么。

var formData = new FormData(document.getElementById('myFormId'));

然后在我的服务中

                var deferred = $q.defer();
                $http.post('myurl', formData, {
                    cache: false,
                    contentType: false,
                    processData: false,
                })
                    .success(function (response) {
                        deferred.resolve(response);
                    })
                    .error(function (reject) {
                        deferred.reject(reject);
                    });
                return deferred.promise;