NodeJS 将文件区块上载到Azure存储blob,文件似乎已损坏

relj7zay  于 2022-12-12  发布在  Node.js
关注(0)|答案(1)|浏览(173)

我尝试上传Excel文件到Azure存储blob块,使用阶段块和来自BlobBlockClient类的commitblock。文件上传似乎成功,但当我尝试下载并打开文件时,它似乎被打破。
我将使用react和node js来完成此操作。
在UI中

const chunkSize = (1024 * 1024) * 25;  // file chunk size

//在此处对文件进行切片并将其发送到API方法

const fileReader = new FileReader();
const from = currentChunkIndexRef.current * chunkSize;
const to = from + chunkSize;
const blob = file.slice(from, to);

fileReader.onload = ((e: any) => uploadChunksToBlob(e, file, obj));
fileReader.readAsDataURL(blob);

// API方法

const uploadChunksToBlob = async (event: any, file: File, obj: any) => {
try {
  const totalChunks = Math.ceil(file.size / chunkSize);
  const uploadChunkURL = `/upload?currentChunk=${currentChunkIndexRef.current}&totalChunks=${totalChunks}&file=${file.name}&type=${file.type}`;
  console.log(event.target.result)
  const fileUpload = await fetch(uploadChunkURL, {
    method: "POST",
    headers: { "Content-Type": "application/octet-stream" },
    body: JSON.stringify(event.target.result),
  });
  const fileUploadJson = await fileUpload.json();
  const isLastChunk = (totalChunks - 1) === currentChunkIndexRef.current;
  if(!isLastChunk) {
    console.log({ Chunk: currentChunkIndexRef.current });
    currentChunkIndexRef.current = currentChunkIndexRef.current + 1;
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    uploadFileToAzureBlob(file, obj);
  } else {
    console.log("File Uploaded")
  }
  // 
} catch (error) {
  console.log("uploadFileToAzureBlob Catch Error" + error);
}

}
//在节点中

const sharedKeyCredential = new StorageSharedKeyCredential(
config.StorageAccountName,
config.StorageAccountAccessKey
);
const pipeline = newPipeline(sharedKeyCredential);
const blobServiceClient = new BlobServiceClient(
`https://${config.StorageAccountName}.blob.core.windows.net`,
 pipeline
 );
const containerName = getContainerName(req.headers.key, req.headers.clientcode);
const identifier = uuid.v4();
const blobName = getBlobName(identifier, file);

const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);

try {

   let bufferObj = Buffer.from(`${file}_${Number(currentChunk)}`, "utf8"); // Create buffer object, specifying utf8 as encoding

   let base64String = bufferObj.toString("base64"); // Encode the Buffer as a base64 string

   blockIds = [...blockIds, base64String];
   const bufferedData = Buffer.from(req.body);

   let resultOfUnitArray = new Uint8Array(bufferedData.length);
   for (let j = 0; j < bufferedData.length; j++) {
     resultOfUnitArray[j] = bufferedData.toString().charCodeAt(j);
   } // Converting string to bytes
   const stageBlockResponse = await blockBlobClient.stageBlock(base64String, resultOfUnitArray, resultOfUnitArray.length, {
  onProgress: (e) => {
    console.log("bytes sent: " + e.loadedBytes);
  }
});
   if ((Number(totalChunks) - 1) === (Number(currentChunk))) {
     const commitblockResponse = await blockBlobClient.commitBlockList(blockIds, {blobHTTPHeaders: req.headers});
     res.json({ uuid: identifier, message: 'File uploaded to Azure Blob storage.' });
   } else {
     res.json({ message: `Current Chunks ${currentChunk} is Successfully Uploaded` });
   }
} catch (err) {
   console.log({ err })
   res.json({ message: err.message });
}

我不知道我做错了什么。
任何帮助都将不胜感激谢谢

ljsrvy3e

ljsrvy3e1#

问题是你把它转换成dataURL,这就是问题所在。
在我看来,你有一个错误的印象,你需要首先将一个blob编码成字符串才能发送它。好吧,你不必这样做,浏览器fetch API能够处理原始的二进制负载。
所以在客户端(浏览器),你不需要通过FileReader,直接发送块blob。

const blob = file.slice(from, to);
// ...

fetch(uploadChunkURL, {
  method: "POST",
  headers: { "Content-Type": "application/octet-stream" },
  body: blob,
});

在服务器(node.js)端,您将收到原始二进制形式的blob,因此您可以简单地将该blob原封不动地转发到Azure存储。

const base64String = Buffer.from(`${file}_${Number(currentChunk)}`, "utf8").toString("base64");
const bufferedData = Buffer.from(req.body);
const stageBlockResponse = await blockBlobClient.stageBlock(
  base64String,
  bufferedData,
  bufferedData.length
);

相关问题