在AngularJS中以相同的请求处理上传文件和JSON格式数据

原文出处:http://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/

我决定写一遍快速介绍这方面的文章,因为很多关于这方面的文档或例子都太片面了。通过这篇文章,我们将学会实现用同样的请求处理来上传任意数量的文件和其他任意格式的数据。这个例子我们会上传一些Json格式的数据和文件。

文件上传指令

首先,我们先建立一个的文件上传的Angular指令。

app.directive('fileUpload', function () {
return {
scope: true, //create a new scope
link: function (scope, el, attrs) {
el.bind('change', function (event) {
var files = event.target.files;
//iterate files since 'multiple' may be specified on the element
for (var i = 0;i<files.length;i++) {
//emit event upward
scope.$emit("fileSelected", { file: files[i] });
}
});
}
};
});
然后,很简单的应用它:

<input type="file" file-upload multiple/>
multiple属性说明这个例子支持用户可以选择多个文件进行上传。

在上面指令中,我们要确定建立一个新的作用域。然后,去监听 input file元素的change事件。当监测到文件对象变化时,将会触发作用域中的事件,以及其父作用域中的事件(向上层)。

创建控制器

接下来,我们要创建一个控制器:

1.创建一个绑定它的模型

2.创建一个文件集合

3.创建一个绑定事件的处理程序,以便我们将文件放入文件集合中。

4.创建一个方法,来上传文件到服务器上。

备注:为了更快捷,我将所有的方法都放到一个控制器中。在大多数情况下,你需要将它们放到不同的处理数据的工厂方法中。

控制器放在这里,这个标注用起来像下面这样(将会显示所有选择的文件)

<div ng-controller="Ctrl">
<input type="file" file-upload multiple/>
<ul>
<li ng-repeat="file in files">{{file.name}}</li>
</ul>
</div>
在控制器中,如下面的代码含有一些很重要的关于如何获得上传到服务器端数据的备注,协议头中 Content-Type 一定要被设置,看起来很诡异吧。

//译者备注:这段很重要,重点之关键

function Ctrl($scope, $http) {

//a simple model to bind to and send to the server
$scope.model = {
name: "",
comments: ""
};

//an array of files selected
$scope.files = [];

//listen for the file selected event
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});

//the save method
$scope.save = function() {
$http({
method: 'POST',
url: "/Api/PostStuff",
//IMPORTANT!!! You might think this should be set to 'multipart/form-data'
// but this is not true because when we are sending up files the request
// needs to include a 'boundary' parameter which identifies the boundary
// name between parts in this multi-part request and setting the Content-type
// manually will not set this boundary parameter. For whatever reason,
// setting the Content-type to 'false' will force the request to automatically
// populate the headers properly including the boundary parameter.
headers: { 'Content-Type': false },
//This method will allow us to change how the data is sent up to the server
// for which we'll need to encapsulate the model data in 'FormData'
transformRequest: function (data) {
var formData = new FormData();
//need to convert our json object to a string version of json otherwise
// the browser will do a 'toString()' on the object which will result
// in the value '[Object object]' on the server.
formData.append("model", angular.toJson(data.model));
//now add all of the assigned files
for (var i = 0; i < data.files; i++) {
//add each file to the form data and iteratively name them
formData.append("file" + i, data.files[i]);
}
return formData;
},
//Create an object that contains the model and files which will be transformed
// in the above transformRequest method
data: { model: $scope.model, files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!");
}).
error(function (data, status, headers, config) {
alert("failed!");
});
};
};

处理服务器端的数据

这个例子展示了用Asp.net Web Api来处理服务器端的数据。我敢肯定,在其他服务器点平台也是相当容易的。

public async Task<HttpResponseMessage> PostStuff()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}

var root = HttpContext.Current.Server.MapPath("~/App_Data/Temp/FileUploads");
Directory.CreateDirectory(root);
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
if (result.FormData["model"] == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}

var model = result.FormData["model"];
//TODO: Do something with the json model which is currently a string



//get the files
foreach (var file in result.FileData)
{
//TODO: Do something with each uploaded file
}

return Request.CreateResponse(HttpStatusCode.OK, "success!");
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值