Сохранение большого двоичного объекта (может быть данных!), Возвращенного вызовом AJAX в хранилище больших двоичных объектов Azure, создает поврежденное изображение
Если я отправляю PDF в API своих поставщиков, они возвращают мне файл.png в виде большого двоичного объекта (см. Обновление 2, так как теперь я не уверен, что они возвращают данные большого двоичного объекта).
Я хочу добавить это в хранилище BLOB-объектов Azure. Используя мой код, указанный ниже, он что-то вставляет, но файл поврежден. Пример: загрузка.png из хранилища BLOB-объектов Azure и попытка открыть его с помощью Paint приводит к следующей ошибке:
Это недопустимый растровый файл или его формат в настоящее время не поддерживается.
Я убедился, что изображение отправлено мне правильно, так как продавец может открыть.png на своей стороне. Мне интересно, нужно ли мне преобразовать его в base64 или сохранить в локальном веб-каталоге перед его загрузкой в хранилище BLOB-объектов Azure.
Вот мой угловой контроллер, который вызывает мой сервер Node/Express для загрузки в Azure после получения возвращенного "изображения":
$.ajax({
url: 'http://myvendorsapi.net/uploadPDF,
type: "POST",
data: formdata,
mimeType: "multipart/form-data",
processData: false,
contentType: false,
crossDomain: true,
success: function (result) {
var containerName = 'container1';
var filename = 'Texture_0.png';
var file = result;
$http.post('/postAdvanced', { containerName: containerName, filename: filename, file: file }).success(function (data) {
console.log("success!");
}, function (err) {
//console.log(err);
});
},
error: function (error) {
console.log("Something went wrong!");
}
})
}
Вот мой бэкэнд Node/Express, который загружает большой двоичный объект в хранилище BLOB-объектов Azure. Это не дает ошибки, но файл не может быть открыт / дает ошибку, указанную выше, при открытии в Paint:
app.post('/postAdvanced', function (req, res, next) {
var containerName = req.body.containerName;
var filename = req.body.filename;
var file = req.body.file;
blobSvc.createBlockBlobFromText(containerName, filename, file, function (error, result, response) {
if (!error) {
res.send(result);
}
else {
console.log(error);
}
});
})
Обновление 1. Ответ, предоставленный здесь, позволяет мне передать URL-адрес API поставщиков для некоторых конечных точек: загрузите файл через веб-сервис и отправьте его в хранилище BLOB-объектов Azure через узел / экспресс
Он работает, так как записывает файл в конечной точке во временную папку. В моем текущем сценарии я загружаю файл PDF, и он возвращает файл изображения, который мне нужно загрузить в хранилище BLOB-объектов Azure. Есть ли способ использовать ответ здесь, но настроить его для файла, который у меня уже есть (так как он мне возвращен), вместо потокового файла с URL?
Обновление 2: при ведении журнала возвращаемого "файла", похоже, что это могут быть данные. Я не уверен, это выглядит так:
Это на самом деле данные, и если да, то как мне сделать это в файл для загрузки?
ОБНОВЛЕНИЕ 3:
Поскольку кажется, что JQuery AJAX не может управлять двоичными возвратами. Я могу "открыть" большой двоичный объект с помощью XMLHTTPResponse следующим образом, но, похоже, я не могу вставить это в Azure, так как он дает мне следующую ошибку:
TypeError: must start with number, buffer, array or string
Вот моя просьба. Обратите внимание, что файл открывается правильно:
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://myvendorsapi/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
console.log(blob);
var containerName = boxContainerName;
var filename = 'Texture_0.png';
$http.post('/postAdvanced', { containerName: containerName, filename: filename, file: blob }).success(function (data) {
//console.log(data);
console.log("success!");
}, function (err) {
//console.log(err);
});
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
3 ответа
createBlockBlobFromText будет работать со строкой или буфером. Вам может понадобиться буфер для хранения двоичного содержимого из-за известной проблемы jQuery.
Для обходного пути есть несколько вариантов:
Вариант 1. Чтение бинарных файлов с использованием jquery ajax
Вариант 2: использовать собственный XMLHttpRequest
Вариант 3: также напишите интерфейс с Node и просмотрите его. Ваш код внешнего интерфейса может выглядеть так:
var request = require('request');
request.post('http://myvendorsapi.net/uploadPDF', function (error, response, body) {
if (!error && response.statusCode == 200) {
var formData = {
containerName: 'container1',
filename: 'Texture_0.png',
file: body
};
request.post({ uri: '/postAdvanced', formData: formData }, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
} else {
console.log('Get snapshot failed!');
}
});
Тогда внутренний код может выглядеть так:
app.post('/postAdvanced', function (req, res, next) {
var containerName = req.body.containerName;
var filename = req.body.filename;
var file = req.body.file;
if (!Buffer.isBuffer(file)) {
// Convert 'file' to a binary buffer
}
var options = { contentType: 'image/png' };
blobSvc.createBlockBlobFromText(containerName, filename, file, options, function (error, result, response) {
if (!error) {
res.send(result);
} else {
console.log(error);
}
});
})
Ниже у меня есть код для загрузки изображения в двоичном и угловом формате с использованием FormData.
Код сервера будет кодом для обработки обычной загрузки файла через форму.
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://vendorapi.net/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
//var objectUrl = URL.createObjectURL(blob);
//window.open(objectUrl);
//console.log(blob);
var formData = new FormData()
formData.append('file', blob);
formData.append('containerName', boxContainerName);
formData.append('filename', 'Texture_0.png');
$http.post('/postAdvancedTest', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (data) {
//console.log(data);
console.log("success!");
// Clear previous 3D render
$('#webGL-container').empty();
// Generated new 3D render
$scope.generate3D();
}, function (err) {
//console.log(err);
});
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
Я решил проблему (благодаря вкладу Янга также). Мне нужно было base64 кодировать данные на стороне клиента, прежде чем передать их на узел для декодирования в файл. Мне нужно было использовать XMLHTTPRequest для правильного получения двоичных данных, так как jQuery AJAX, похоже, имеет проблему с возвратом (см. Здесь: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/).
Вот мой интерфейс:
var form = document.forms.namedItem("fileinfo");
form.addEventListener('submit', function (ev) {
var oData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.responseType = "arraybuffer";
xhr.open("POST", "http://vendorapi.net/Upload", true);
xhr.onload = function (oEvent) {
if (xhr.status == 200) {
var blob = new Blob([xhr.response], { type: "image/png" });
//var objectUrl = URL.createObjectURL(blob);
//window.open(objectUrl);
console.log(blob);
var blobToBase64 = function(blob, cb) {
var reader = new FileReader();
reader.onload = function() {
var dataUrl = reader.result;
var base64 = dataUrl.split(',')[1];
cb(base64);
};
reader.readAsDataURL(blob);
};
blobToBase64(blob, function(base64){ // encode
var update = {'blob': base64};
var containerName = boxContainerName;
var filename = 'Texture_0.png';
$http.post('/postAdvancedTest', { containerName: containerName, filename: filename, file: base64}).success(function (data) {
//console.log(data);
console.log("success!");
// Clear previous 3D render
$('#webGL-container').empty();
// Generated new 3D render
$scope.generate3D();
}, function (err) {
//console.log(err);
});
})
} else {
oOutput.innerHTML = "Error " + xhr.status + " occurred when trying to upload your file.<br \/>";
}
};
xhr.send(oData);
ev.preventDefault();
}, false);
Бэкэнд узла:
app.post('/postAdvancedTest', function (req, res) {
var containerName = req.body.containerName
var filename = req.body.filename;
var file = req.body.file;
var buf = new Buffer(file, 'base64'); // decode
var tmpBasePath = 'upload/'; //this folder is to save files download from vendor URL, and should be created in the root directory previously.
var tmpFolder = tmpBasePath + containerName + '/';
// Create unique temp directory to store files
mkdirp(tmpFolder, function (err) {
if (err) console.error(err)
else console.log('Directory Created')
});
// This is the location of download files, e.g. 'upload/Texture_0.png'
var tmpFileSavedLocation = tmpFolder + filename;
fs.writeFile(tmpFileSavedLocation, buf, function (err) {
if (err) {
console.log("err", err);
} else {
//return res.json({ 'status': 'success' });
blobSvc.createBlockBlobFromLocalFile(containerName, filename, tmpFileSavedLocation, function (error, result, response) {
if (!error) {
console.log("Uploaded" + result);
res.send(containerName);
}
else {
console.log(error);
}
});
}
})
})