Angularjs $ http发布文件和表单数据

我有下面的请求在Python中

import requests, json, io cookie = {} payload = {"Name":"abc"} url = "/test" file = "out/test.json" fi = {'file': ('file', open(file) )} r = requests.post("http://192.168.1.1:8080" + url, data=payload, files=fi, cookies=cookie) print(r.text) 

它发送一个文件,并将字段形成到后端。 我怎样才能做到这一点(发送文件+表单字段)Angular $ http。 目前,我这样做,但不知道如何发送文件。

 var payload = {"Name":"abc"}; $http.post('/test', payload) .success(function (res) { //success }); 

我最近写了一个支持本地多个file upload的指令。 我创build的解决scheme依赖于一个服务来填补你与$ http服务标识的空白。 我还包括一个指令,它为您的angular度模块提供一个简单的API来发布文件和数据。

用法示例:

 <lvl-file-upload auto-upload='false' choose-file-button-text='Choose files' upload-file-button-text='Upload files' upload-url='http://localhost:3000/files' max-files='10' max-file-size-mb='5' get-additional-data='getData(files)' on-done='done(files, data)' on-progress='progress(percentDone)' on-error='error(files, type, msg)'/> 

你可以在github上find代码 ,并在我的博客 上find文档

这将取决于您在Web框架中处理文件,但是我创build的解决scheme提供了将数据传送到服务器的angular度接口。 您需要编写的angular码是为了响应上传事件

 angular .module('app', ['lvl.directives.fileupload']) .controller('ctl', ['$scope', function($scope) { $scope.done = function(files,data} { /*do something when the upload completes*/ }; $scope.progress = function(percentDone) { /*do something when progress is reported*/ }; $scope.error = function(file, type, msg) { /*do something if an error occurs*/ }; $scope.getAdditionalData = function() { /* return additional data to be posted to the server*/ }; }); 

当我不得不同时上传文件和发送用户令牌信息时,我也遇到了类似的问题。 transformRequestFormData帮助:

  $http({ method: 'POST', url: '/upload-file', headers: { 'Content-Type': 'multipart/form-data' }, data: { email: Utils.getUserInfo().email, token: Utils.getUserInfo().token, upload: $scope.file }, transformRequest: function (data, headersGetter) { var formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); var headers = headersGetter(); delete headers['Content-Type']; return formData; } }) .success(function (data) { }) .error(function (data, status) { }); 

获取文件$scope.file我使用自定义指令:

 app.directive('file', function () { return { scope: { file: '=' }, link: function (scope, el, attrs) { el.bind('change', function (event) { var file = event.target.files[0]; scope.file = file ? file : undefined; scope.$apply(); }); } }; }); 

HTML:

 <input type="file" file="file" required /> 

我无法得到帕维尔的答案在发布到Web.Api应用程序时工作。

这个问题似乎与删除标题。

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

为了确保浏览器允许默认Content-Type和边界参数,我需要将Content-Type设置为undefined。 使用Pavel的例子,边界从未被设置,导致400 HTTPexception。

关键是删除删除上面显示的标题的代码,并手动将标题内容types设置为空。 从而允许浏览器设置属性。

 headers: {'Content-Type': undefined} 

这是一个完整的例子。

 $scope.Submit = form => { $http({ method: 'POST', url: 'api/FileTest', headers: {'Content-Type': undefined}, data: { FullName: $scope.FullName, Email: $scope.Email, File1: $scope.file }, transformRequest: function (data, headersGetter) { var formData = new FormData(); angular.forEach(data, function (value, key) { formData.append(key, value); }); return formData; } }) .success(function (data) { }) .error(function (data, status) { }); return false; } 

您也可以使用HTML5上传。 你可以使用这个AJAX上传器 。

JS代码基本上是:

  $scope.doPhotoUpload = function () { // .. var myUploader = new uploader(document.getElementById('file_upload_element_id'), options); myUploader.send(); // .. } 

它从HTMLinput元素读取

 <input id="file_upload_element_id" type="file" onchange="angular.element(this).scope().doPhotoUpload()"> 

这里是我的解决scheme:

 // Controller $scope.uploadImg = function( files ) { $scope.data.avatar = files[0]; } $scope.update = function() { var formData = new FormData(); formData.append('desc', data.desc); formData.append('avatar', data.avatar); SomeService.upload( formData ); } // Service upload: function( formData ) { var deferred = $q.defer(); var url = "/upload" ; var request = { "url": url, "method": "POST", "data": formData, "headers": { 'Content-Type' : undefined // important } }; console.log(request); $http(request).success(function(data){ deferred.resolve(data); }).error(function(error){ deferred.reject(error); }); return deferred.promise; } // backend use express and multer // a part of the code var multer = require('multer'); var storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, '../public/img') }, filename: function (req, file, cb) { cb(null, file.fieldname + '-' + Date.now() + '.jpg'); } }) var upload = multer({ storage: storage }) app.post('/upload', upload.single('avatar'), function(req, res, next) { // do something console.log(req.body); res.send(req.body); }); 
 <div> <input type="file" accept="image/*" onchange="angular.element( this ).scope().uploadImg( this.files )"> <textarea ng-model="data.desc" /> <button type="button" ng-click="update()">Update</button> </div> 

还有其他的解决scheme,你可以看看http://ngmodules.org/modules/ngUpload这里讨论的file upload器集成angularjs

在我的解决scheme中,我有

 $scope.uploadVideo = function(){ var uploadUrl = "/api/uploadEvent"; //obj with data, that can be one input or form file = $scope.video; var fd = new FormData(); //check file form on being for (var obj in file) { if (file[obj] || file[obj] == 0) { fd.append(obj, file[obj]); } } //open XHR request var xhr = new XMLHttpRequest(); // $apply to rendering progress bar for any chunking update xhr.upload.onprogress = function(event) { $scope.uploadStatus = { loaded: event.loaded, total: event.total }; $scope.$apply(); }; xhr.onload = xhr.onerror = function(e) { if (this.status == 200 || this.status == 201) { //sucess $scope.uploadStatus = { loaded: 0, total: 0 }; //this is for my solution $scope.video = {}; $scope.vm.model.push(JSON.parse(e.currentTarget.response)); $scope.$apply(); } else { //on else status } }; xhr.open("POST", uploadUrl, true); //token for upload, thit for my solution xhr.setRequestHeader("Authorization", "JWT " + window.localStorage.token); //send xhr.send(fd); }; 

}

请看看我的实现。 您可以将以下function包装到服务中:

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

请注意,该file参数是一个Blob 。 如果你有一个文件的base64版本 – 它可以很容易地更改为Blob如下所示:

 fetch(base64).then(function(response) { return response.blob(); }).then(console.info).catch(console.error);