createBlockBlobFromStream() 覆盖现有内容而不是追加

Posted

技术标签:

【中文标题】createBlockBlobFromStream() 覆盖现有内容而不是追加【英文标题】:createBlockBlobFromStream() is overriding existing content instead of appending 【发布时间】:2021-09-18 05:12:50 【问题描述】:

我们处理非常大的文件,因此我们将它们分成 20mb 的块,然后调用上传函数将它们上传到 blob 存储。我在节点 js 中调用 upload(),我发现上传时丢失了一些东西。每次只上传 20mb,我怀疑 nodejs 是覆盖内容而不是附加流。

有人可以帮忙解决吗?

const chunkSize = Number(request.headers["x-content-length"]);
const userrole = request.headers["x-userrole"];
const pathname = request.headers["x-pathname"];

var form = new multiparty.Form();
form.parse(request, function (err, fields, files) 
if (files && files["payload"] && files["payload"].length > 0) 
var fileContent = fs.readFileSync(files["payload"][0].path);
// log.error('fields',fields['Content-Type'])
fs.unlink(files["payload"][0].path, function (err) 
if (err) 
log.error("Error in unlink payload:" + err);

);
var size = fileContent.length;
if (size !== chunkSize) 
sendBadRequest(response, "Chunk uploading was not completed");
return;

//converting chunk[buffers] to readable stream
const stream = Readable.from(fileContent);
var options = 
contentSettings: 
contentType: fields['Content-Type']


blobService.createBlockBlobFromStream(containerName, pathname, stream, size, options, error => 
);

标题:

X-id: 6023f6f53601233c080b1369
X-Chunk-Id: 38
X-Content-Id: 43bfdbf4ddd1d7b5cd787dc212be8691d8dd147017a2344cb0851978b2d983c075c26c6082fd27a5147742b030856b0d71549e4d208d1c3c9d94f957e7ed1c92
X-pathname: 6023f6ae3601233c080b1365/spe10_lgr311_2021-02-10_09-08-37/output/800mb.inc

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqodrlQNFytNS9wAc
X-Content-Name: 800mb.inc

【问题讨论】:

【参考方案1】:

问题是您正在使用createBlockBlobFromStream,它将覆盖 blob 的内容。此方法用于在单个请求中创建 blob(即完整的 blob 数据作为输入传递)。来自文档here

从流中上传块 Blob。如果 blob 已存在于 服务,它将被覆盖。为了避免覆盖,而是 如果 blob 存在则抛出错误,请传入 accessConditions 选项对象中的参数。

在您的情况下,您正在上传数据块。您需要做的是对您上传的每个块使用 createBlockFromStream 方法。

上传所有块后,您需要调用 commitBlocks 方法来创建 blob。

更新

我们如何生成blockId?

块 id 只是一个字符串。要记住的关键是,当您调用createBlockFromStream 时,您发送的每个块的块ID 的长度必须相同。例如,您不能使用1,2,3,4,5,6,7,8,9,10,11...。您将不得不使用01,02,03,04,05,06,07,08,09,10,11... 之类的东西,以便它们具有相同的长度。您可以为此目的使用 GUID。此外,block id 的最大长度为 50 个字符。

它应该对所有人都是独一无二的吗?

是的。对于 blob,块 id 必须是唯一的,否则它将覆盖上一个使用相同 id 上传的块的内容。

你可以展示示例代码,以便我可以尝试类似的方式 实施?

请看here

基本上,这个想法非常简单:在客户端,您将文件分块并分别发送每个块。您要做的除了发送该数据外,您还将发送一个块 ID 字符串。您还需要在客户端保留该块 ID。您将对文件的所有块重复相同的过程。

一旦所有区块上传成功,您将向您的服务器再次发出请求并发送所有区块 ID 的列表。届时您的服务器将调用 commitBlocks 来创建 blob。

请注意,您上次请求中的块 ID 顺序很重要。 Azure 存储服务将使用此信息将 blob 拼接在一起。

【讨论】:

我们如何生成 blockId ,它应该对所有人都是唯一的吗?你可以展示示例代码,以便我可以尝试类似的方式来实现吗? 更新了我的答案。 HTH。 多一个请求是什么意思?不是在同一个API中吗?只需检查 eof 是否调用 commitblocks? 不确定你的意思。你能详细说明你的评论吗?提交块列表是与 Put 块操作分开的操作。使用提交块列表向 Azure 存储服务发出信号,以通过组合所有块来创建 blob。您可能会发现此链接有助于理解它:docs.microsoft.com/en-us/rest/api/storageservices/…。 实际上我对何时调用 commitblock() 感到有些困惑,它是在用于 createblockfromstream() 的同一 API 中还是需要调用单独的 API?

以上是关于createBlockBlobFromStream() 覆盖现有内容而不是追加的主要内容,如果未能解决你的问题,请参考以下文章