我有一个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
,但不设置多部分的值。
我错过了什么吗?这个功能不应该像这样工作吗?
谢谢!
答案 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-Type
为multipart/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;