programing

AngularJS: $리소스(솔루션)를 사용하여 파일 업로드

newstyles 2023. 3. 25. 10:55

AngularJS: $리소스(솔루션)를 사용하여 파일 업로드

Angular를 사용하고 있습니다.JS를 사용하여RESTful웹 서비스, 사용$resource노출되는 다양한 실체를 추상화합니다.이 엔티티 중 일부는 이미지이기 때문에save의 작용$resource"object" - 동일한 요청 내에서 이진 데이터와 텍스트 필드를 모두 보냅니다.

Angular 사용방법JS의$resource데이터를 전송하고 이미지를 하나의 안전한 웹 서비스로 업로드하는 서비스POST요청하시겠습니까?

이 문제에 대한 해결책을 찾지 못했습니다. $resource 액션을 사용하여 파일을 업로드하는 것입니다.

예를 들어, 델의 RESTful 서비스를 이용하면, 델의 RESTful 서비스를 이용하면,/images/엔드 포인트각각Image에는 이미지 파일을 가리키는 제목, 설명 및 경로가 있습니다.RESTful 서비스를 이용하면 모든 것을 얻을 수 있습니다(GET /images/, 1개(GET /images/1또는 하나를 추가합니다( ).POST /imagesAngular를 사용하면 $resource 서비스를 사용하여 이 작업을 쉽게 수행할 수 있지만, 세 번째 작업에 필요한 파일 업로드를 바로 수행할 수 없습니다(또한 조만간 지원할 예정은 없는같습니다).그렇다면 매우 편리한 $resource 서비스가 파일 업로드를 처리할 수 없다면 어떻게 해야 할까요?알고 보니 꽤 쉬웠어요!

데이터 바인딩은 Angular JS의 뛰어난 기능 중 하나이기 때문에 사용합니다.다음과 같은 HTML 양식이 있습니다.

<form class="form" name="form" novalidate ng-submit="submit()">
    <div class="form-group">
        <input class="form-control" ng-model="newImage.title" placeholder="Title" required>
    </div>
    <div class="form-group">
        <input class="form-control" ng-model="newImage.description" placeholder="Description">
    </div>
    <div class="form-group">
        <input type="file" files-model="newImage.image" required >
    </div>

    <div class="form-group clearfix">
        <button class="btn btn-success pull-right" type="submit" ng-disabled="form.$invalid">Save</button>
    </div>
</form>

보시다시피 두 개의 텍스트가 있습니다.input각 필드가 단일 객체의 속성에 바인딩되어 있습니다.newImage. 파일input의 속성과도 바인드 되어 있습니다.newImage오브젝트입니다만, 이번에는 여기서 바로 취합한 커스텀 디렉티브를 사용했습니다.이 지시는 파일의 내용이 항상inputFileList 객체가 바인딩된 속성 내에 배치되는 대신fakepath(이것은 앵글의 표준적인 행동입니다).

컨트롤러 코드는 다음과 같습니다.

angular.module('clientApp')
.controller('MainCtrl', function ($scope, $resource) {
    var Image = $resource('http://localhost:3000/images/:id', {id: "@_id"});

    Image.get(function(result) {
        if (result.status != 'OK')
            throw result.status;

        $scope.images = result.data;
    })

    $scope.newImage = {};

    $scope.submit = function() {
        Image.save($scope.newImage, function(result) {
            if (result.status != 'OK')
                throw result.status;

            $scope.images.push(result.data);
        });
    }
}); 

(이 경우 노드를 실행하고 있습니다.포트 3000에 있는 로컬머신의 JS서버에서 응답은 JSon 오브젝트입니다.status필드 및 옵션data필드)를 참조해 주세요.

파일 업로드가 작동하려면 앱 객체의 .config 호출 내에서 $http 서비스를 적절하게 구성해야 합니다.특히 각 포스트 요청의 데이터를 FormData 개체로 변환하여 올바른 형식으로 서버로 전송해야 합니다.

angular.module('clientApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute'
])
.config(function ($httpProvider) {
  $httpProvider.defaults.transformRequest = function(data) {
    if (data === undefined)
      return data;

    var fd = new FormData();
    angular.forEach(data, function(value, key) {
      if (value instanceof FileList) {
        if (value.length == 1) {
          fd.append(key, value[0]);
        } else {
          angular.forEach(value, function(file, index) {
            fd.append(key + '_' + index, file);
          });
        }
      } else {
        fd.append(key, value);
      }
    });

    return fd;
  }

  $httpProvider.defaults.headers.post['Content-Type'] = undefined;
});

Content-Type는 「이행」으로 .undefined으로 「」로 하기 위해서입니다.multipart/form-data는 경계값을 설정하지 않고 서버는 요구를 올바르게 해석할 수 없습니다.

로로그그그그다다, 그럼 에는 '어울릴 수 .$resource로로 합니다.save()표준 데이터 필드와 파일을 모두 포함하는 객체.

경고 여기에는 몇 가지 제한이 있습니다.

  1. 오래된 브라우저에서는 작동하지 않습니다.죄송합니다.
  2. 모델에 다음과 같은 문서가 포함되어 있는 경우

    { title: "A title", attributes: { fancy: true, colored: false, nsfw: true }, image: null }

    그에 따라 transformRequest 함수를 리팩터링해야 합니다.예를 들어, 네스트된 오브젝트를 상대편에서 해석할 수 있다면

  3. 영어가 주 언어가 아니기 때문에 설명이 불분명할 경우 다시 표현해 보겠습니다.

  4. 이것은 단지 예시일 뿐이다.응용 프로그램이 수행해야 하는 작업에 따라 이 기능을 확장할 수 있습니다.

도움이 됐으면 좋겠네요, 건배!

편집:

@david가 지적한 바와 같이 이 동작을 정의하는 것이 보다 덜 침습적인 해결책이 될 것입니다.$resource실제로으로 Angular Angular모든 요구를 변환하지 됩니다.$resource음음음같 뭇매하다

$resource('http://localhost:3000/images/:id', {id: "@_id"}, { 
    save: { 
        method: 'POST', 
        transformRequest: '<THE TRANSFORMATION METHOD DEFINED ABOVE>', 
        headers: '<SEE BELOW>' 
    } 
});

헤더에 대해서는 요건을 충족하는 헤더를 작성해야 합니다.할 필요가 은, 「 」의 「 」의 「 。'Content-Type'(「」로 )undefined.

$resource" "를 사용한 FormData나는 다음과 같은 것을 알았다.

angular.module('app', [
    'ngResource'
])

.factory('Post', function ($resource) {
    return $resource('api/post/:id', { id: "@id" }, {
        create: {
            method: "POST",
            transformRequest: angular.identity,
            headers: { 'Content-Type': undefined }
        }
    });
})

.controller('PostCtrl', function (Post) {
    var self = this;

    this.createPost = function (data) {
        var fd = new FormData();
        for (var key in data) {
            fd.append(key, data[key]);
        }

        Post.create({}, fd).$promise.then(function (res) {
            self.newPost = res;
        }).catch(function (err) {
            self.newPostError = true;
            throw err;
        });
    };

});

이 방법은 1.4.0+에서는 동작하지 않습니다.자세한 내용은 각도를 확인하십시오.JS changelog(검색)$http: due to 5da1256이 문제를 해결합니다.이는 실제로는 Angular에서 의도하지 않은(따라서 제거된) 동작입니다.JS.

이 기능은 폼 데이터를 FormData 개체로 변환(또는 추가)하기 위해 고안되었습니다.서비스로 쓸 수 있을 것 같아요.

는 어느 의 안에 있어야 .transformRequest inside 「 」$httpProvider또는 서비스로 사용할 수 있습니다. ★★★★★★★★★★★★★★★★.Content-Type【NULL】【NULL】【NULL】【NULL】【NULL】【NOLL】이러한 설정은 이 로직을 배치하는 컨텍스트에 따라 달라집니다.를 들어, 「」의 입니다.transformRequest리소스를 구성할 때 다음 작업을 수행합니다.

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

, 「」를 설정하고 있는 는,$httpProvider위의 답변에 기재된 방법을 사용할 수 있습니다.

가 ᄋ자 안에 배치되어 .transformRequest리소스 메서드.

appServices.factory('SomeResource', ['$resource', function($resource) {
  return $resource('some_resource/:id', null, {
    'save': {
      method: 'POST',
      transformRequest: function(data, headersGetter) {
        // Here we set the Content-Type header to null.
        var headers = headersGetter();
        headers['Content-Type'] = undefined;

        // And here begins the logic which could be used somewhere else
        // as noted above.
        if (data == undefined) {
          return data;
        }

        var fd = new FormData();

        var createKey = function(_keys_, currentKey) {
          var keys = angular.copy(_keys_);
          keys.push(currentKey);
          formKey = keys.shift()

          if (keys.length) {
            formKey += "[" + keys.join("][") + "]"
          }

          return formKey;
        }

        var addToFd = function(object, keys) {
          angular.forEach(object, function(value, key) {
            var formKey = createKey(keys, key);

            if (value instanceof File) {
              fd.append(formKey, value);
            } else if (value instanceof FileList) {
              if (value.length == 1) {
                fd.append(formKey, value[0]);
              } else {
                angular.forEach(value, function(file, index) {
                  fd.append(formKey + '[' + index + ']', file);
                });
              }
            } else if (value && (typeof value == 'object' || typeof value == 'array')) {
              var _keys = angular.copy(keys);
              _keys.push(key)
              addToFd(value, _keys);
            } else {
              fd.append(formKey, value);
            }
          });
        }

        addToFd(data, []);

        return fd;
      }
    }
  })
}]);

이를 통해 다음 작업을 문제 없이 수행할 수 있습니다.

var data = { 
  foo: "Bar",
  foobar: {
    baz: true
  },
  fooFile: someFile // instance of File or FileList
}

SomeResource.save(data);

언급URL : https://stackoverflow.com/questions/21115771/angularjs-upload-files-using-resource-solution