Многостраничный запрос с AngularJS
У меня есть конечная точка 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). Прочитав еще несколько (qaru.site/info/277357/...), я попытался использовать Blob для этого, объект customFormData
выглядит следующим образом (немного беспорядок, в основном первая часть будет 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), правильные значения задаются в multiparts, но contentType
не установлены. С 2) установлены contentType
, но не значения для множителей.
Я что-то упустил? Эта функция не должна работать так?
Спасибо!
Ответы
Ответ 1
Самый простой способ загрузки файлов в 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 замечательный блогпост.
Ответ 2
Вы пробовали что-то вроде этого:
$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;
};
Ответ 3
Я точно решаю ту же проблему.
После некоторых тестов у меня была такая ситуация, которую вы описали:
В основном, что происходит с 1) правильные значения задаются в multiparts, но contentType не заданы. С 2) задан тип contentType, но не значения для multiparts.
Чтобы устранить эту проблему, мне пришлось использовать Blob и Post Ajax вместо $http Post.
Кажется, что $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
Вы можете использовать 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 с помощью "multipart/form-data", файла и объекта данных как JSON отдельно.
Для получения дополнительной информации вы можете перейти по ссылке выше и посмотреть ReadMe.md плагина.
Я знаю, что мой подход немного отличается от того, который вы сейчас используете, но цель такая же.
Ответ 5
что я сделал, чтобы решить это.
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;