我正在开发一个可以将大文件上传到Azure Blob存储中的Web应用程序。
作为后端,我在nodeJS中使用Windows Azure移动服务(Web应用程序将为移动设备生成内容)。
我的客户端可以成功地将数据块发送到后端,一切看起来都很好,但最后,上传的文件是空的。数据上传是按照本教程编写的:当文件足够小以便在单个请求中上传时,它可以正常工作。当文件需要以块的形式分解时,该过程失败。它使用教程中的ReadableStreamBuffer。
有人能帮助我吗?
这里是代码:
后端:createBlobBlockFromStream
[...]
//Get references
var azure = require('azure');
var qs = require('querystring');
var appSettings = require('mobileservice-config').appSettings;
var accountName = appSettings.STORAGE_NAME;
var accountKey = appSettings.STORAGE_KEY;
var host = accountName + '.blob.core.windows.net';
var container = "zips";
//console.log(request.body);
var blobName = request.body.file;
var blobExt = request.body.ext;
var blockId = request.body.blockId;
var data = new Buffer(request.body.data, "base64");
var stream = new ReadableStreamBuffer(data);
var streamLen = stream.size();
var blobFull = blobName+"."+blobExt;
console.log("BlobFull: "+blobFull+"; id: "+blockId+"; len: "+streamLen+"; "+stream);
var blobService = azure.createBlobService(accountName, accountKey, host);
//console.log("blockId: "+blockId+"; container: "+container+";\nblobFull: "+blobFull+"streamLen: "+streamLen);
blobService.createBlobBlockFromStream(blockId, container, blobFull, stream, streamLen,
function(error, response){
if(error){
request.respond(statusCodes.INTERNAL_SERVER_ERROR, error);
} else {
request.respond(statusCodes.OK, {message : "block created"});
}
});
[...]
后端:commitBlobBlock
[...]
var azure = require('azure');
var qs = require('querystring');
var appSettings = require('mobileservice-config').appSettings;
var accountName = appSettings.STORAGE_NAME;
var accountKey = appSettings.STORAGE_KEY;
var host = accountName + '.blob.core.windows.net';
var container = "zips";
var blobName = request.body.file;
var blobExt = request.body.ext;
var blobFull = blobName+"."+blobExt;
var blockIdList = request.body.blockList;
console.log("blobFull: "+blobFull+"; blockIdList: "+JSON.stringify(blockIdList));
var blobService = azure.createBlobService(accountName, accountKey, host);
blobService.commitBlobBlocks(container, blobFull, blockIdList, function(error, result){
if(error){
request.respond(statusCodes.INTERNAL_SERVER_ERROR, error);
} else {
request.respond(statusCodes.OK, result);
blobService.listBlobBlocks(container, blobFull)
}
});
[...]
第二种方法返回正确的blockId列表,所以我认为该过程的第二部分工作正常。我认为这是第一种无法在块内写入数据的方法,就像它创建了一些空块一样。
在客户端,我使用FileReader JS API将文件读作ArrayBuffer。
然后我使用以下代码将其转换为Base4编码的字符串。如果我在一次调用中创建blob,这种方法非常有效,适用于小文件。
[...]
//data contains the ArrayBuffer read by the FileReader API
var requestData = new Uint8Array(data);
var binary = "";
for (var i = 0; i < requestData.length; i++) {
binary += String.fromCharCode( requestData[ i ] );
}
[...]
有什么想法吗?
谢谢你, RIC
答案 0 :(得分:0)
您使用的是哪个版本的Azure Storage Node.js SDK?看起来您可能正在使用旧版本;如果是这样我会建议升级到最新版本(撰写本文时为0.3.0)。我们用新库改进了许多领域,包括blob上传;你可能会遇到一个已修复过的bug。请注意,版本之间可能存在重大变化。
下载最新的Node.js模块(代码也在Github上) https://www.npmjs.org/package/azure-storage
阅读我们的博客文章:针对Node.js的Microsoft Azure存储客户端模块v.0.2.0 http://blogs.msdn.com/b/windowsazurestorage/archive/2014/06/26/microsoft-azure-storage-client-module-for-node-js-v-0-2-0.aspx
如果这不是问题,您是否可以检查Fiddler跟踪(或等效信息)以查看是否将原始数据块发送到服务?
答案 1 :(得分:0)
不太确定你是否仍然遇到这个问题,但我遇到了完全相同的事情并遇到了这个寻找解决方案。好吧,我找到了一个,虽然是id。
我的问题不在于我如何推动该块,而是我如何实现它。我的小代理服务器不知道先前的提交,它只是推送它发送的数据并提交它。麻烦的是我没有提供先前提交的块的提交消息,所以每次都用当前的提交覆盖它们。
所以我的解决方案:
var opts = {
UncommittedBlocks: [IdOfJustCommitedBlock],
CommittedBlocks: [IdsOfPreviouslyCommittedBlocks]
}
blobService.commitBlobBlocks('containerName', 'blobName', opts, function(e, r){});
对我而言,破坏一切的是opts对象的格式。我没有提供以前提交的块名称数组。值得注意的是,我必须将现有的块名称base64解码为:
blobService.listBlobBlocks('containerName', 'fileName', 'type IE committed', fn)
返回名称为base64 encoded的每个块的对象。
为了完整性,这里是我如何推动我的块,req来自快速路线:
var blobId = blobService.getBlockId('blobName', 'lengthOfPreviouslyCommittedArray + 1 as Int');
var length = req.headers['content-length'];
blobService.createBlobBlockFromStream(blobId, 'containerName', 'blobName', req, length, fn);
同样在上传时我遇到了一个奇怪的问题,即内容长度标题导致它中断,因此必须从req.headers对象中删除它。
希望这有帮助并且足够详细。