web-dev-qa-db-ja.com

AngularJSを使用したマルチパートリクエスト

file(ファイルシステムファイル)とdata(JSONオブジェクト)の2つの部分で構成されるマルチパートHTTPリクエストを送信する必要があるAPIエンドポイントがあります。

いくつかの調査の後、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/689216Blob、このように見えるcustomFormDataオブジェクト(ちょっとした混乱、基本的に最初の部分はcontentTypeapplication/json、2番目の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;
 };

この2番目のアプローチは、リクエストの各部分に正しいcontentTypeを設定しますが、部分に値を設定しません。

基本的に何が起こるかは1)で、正しい値はマルチパートに設定されますが、contentTypeは設定されません。 2)では、contentTypeが設定されますが、マルチパートの値は設定されません。

何か不足していますか?この機能はこのように動作するはずではありませんか?

ありがとう!

19
Adrian Marinica

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(){
});

絶対に不可欠なのは、configオブジェクトの次の2つのプロパティです。

transformRequest: angular.identity

angularのデフォルトのシリアル化をオーバーライドし、データをそのまま残します。

headers: {'Content-Type': undefined }

ブラウザが正しいContent-Typemultipart/form-dataとして検出し、正しい境界を埋めるようにします。

私のために他に何も働いていません! Lady Louthan's wonderful blogpost のご厚意による。

30
Sensei James

まったく同じ問題を解決するだけです。

いくつかのテストの後、あなたが説明したこの状況がありました:

基本的に1で何が起こるか)正しい値はマルチパートに設定されますが、contentTypeは設定されません。 2)では、contentTypeが設定されますが、マルチパートの値は設定されません。

この問題を解決するには、Blobと$ http Postの代わりにPost Ajaxを使用する必要がありました。

この場合、$ httpは正しく機能しないようです。

コード:

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

リクエスト:

    $.ajax({
      url: url,
      data: formData,
      cache: false,
      contentType: false,
      processData: false,
      type: 'POST',
      success: function(response) {
        deferred.resolve(response);
        $rootScope.requestInProgress = false;
      },
      error: function(error) {
        deferred.reject(error);
        $rootScope.requestInProgress = false;
      }
    });
4
Lucas Leal

このようなことを試しましたか:

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

https://github.com/danialfarid/ng-file-upload/ を使用できます。

このファイルアップローダーには、上記の質問で述べたように、ファイルとデータ(JSON形式)を別々に送信するための規定があります。

例:-

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リクエストを 'multipart/form-data'、ファイル、およびデータオブジェクトと共にJSONとして個別に送信できます。

詳細については、上記のリンクにアクセスして、プラグインのReadMe.mdをご覧ください。

私のアプローチは現在フォローしているアプローチとは少し異なりますが、目的は同じです。

2
Ravi Teja

これを解決するためにやったことは。

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;
0
themightysapien