You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Blob已提交2个块,但获取Blob仅返回第一个块的问题排查

问题排查:Azure Blob 块上传后仅返回第一个块

我使用Azure REST API执行Put Block和Put Block List操作,操作均显示成功完成。通过GET请求访问https://accountname.blob.core.windows.net/container/myblobname?comp=blocklist查询块列表,返回结果如下:

<?xml version="1.0" encoding="utf-8"?>
<BlockList>
    <CommittedBlocks>
        <Block>
            <Name>MjAyMy0wNy0xM1QxNTo0Mjo0MS4xM</Name>
            <Size>1048057</Size>
        </Block>
        <Block>
            <Name>MjAyMy0wNy0xM1QxNTo0MzoxMC44M</Name>
            <Size>460893</Size>
        </Block>
    </CommittedBlocks>
</BlockList>

这两个块对应一个视频文件,但直接访问https://accountname.blob.core.windows.net/container/myblobname获取完整视频时,仅返回第一个块,第二个块缺失。以下是我的代码:

export const uploadLongFile = async (param: any) => {
  const {path, filename, mime} = param;
  const blockSize = 1 * 1024 * 1024; // 1MB
  const fileSize = param?.size;
  const blockCount = Math.ceil(fileSize / blockSize);
  const sasContainerUri =  Config.CONTAINER_URI;
  const customBlobName = Math.random().toString(16).slice(2);
  const fileExtension = (filename ?? path).split('.').pop();
  const newFileName = `${customBlobName}.${fileExtension}`;
  const container = 'images';
  const assetPath = `${sasContainerUri}/${container}/${newFileName}`;
  const sasToken = Config.SAS_TOKEN; // you may need to play with other html verbs in this string e.g., `sp`, `ss` e.t.c.
  const blockIds: any[] = [];
  const videoChunks: any[] = [];
  const timeInterval = param?.duration / 1000 / blockCount;
  const chunks = await TrimWithIntervalVideo(path, timeInterval);// Trim video into blockCount chunks
  let totalSize = 0;
  for (let i = 0; i < blockCount; i++) {
    let dataString = encodeURIComponent(encode(new Date().toISOString()));
    blockIds.push(dataString);
    let info = await ReactNativeBlobUtil.fs.stat(videoChunks[i]);
    let chunkPath =
      i < 10
        ? `${chunks?.url}00${i}.${chunks?.ext}`
        : i < 100
        ? `${chunks?.url}0${i}.${chunks?.ext}`
        : `${chunks?.url}${i}.${chunks?.ext}`;
    videoChunks.push(chunkPath);
    totalSize += info.size;
    await stageBlock(
      blockIds[i],
      videoChunks[i],
      `${assetPath}?${sasToken}`,
      info?.size,
    );
    if (i === blockCount - 1) {
      commitBlockList(blockIds, totalSize, `${assetPath}?${sasToken}`);
    }
  }
};
const stageBlock = async (
  blockId?: any,
  chunk?: any,
  url?: any,
  length?: any,
) => {
  const res = await ReactNativeBlobUtil.fetch(
    'PUT',
    `${url}&comp=block&blockid=${blockId}`,
    {
      'x-ms-date': new Date().toUTCString(),
      'content-length': `${length}`,
    },
// Change BASE64 encoded data to a file path with prefix `ReactNativeBlobUtil-file://`.
// Or simply wrap the file path with ReactNativeBlobUtil.wrap(
    ReactNativeBlobUtil.wrap(chunk),
  ).catch(error => console.log({error}));
  console.log({res});
};
const commitBlockList = async (blockIds: any, length: any, url: any) => {
  let blockList: any[] = blockIds?.map(
    (value: string) => `<Latest>${value}</Latest>`,
  );
  let ff = blockList
    .toString()
    .replace('[', '')
    .replace(']', '')
    .replace(',', '\n');
  console.log({url}, {blockList}, {ff});
  const res2 = await ReactNativeBlobUtil.fetch(
    'PUT',
    `${url}&comp=blocklist`,
    {
      'x-ms-date': new Date().toUTCString(),
      'content-length': `${length}`,
      'content-type': 'text/plain; charset=UTF-8',
    },
    `<?xml version="1.0" encoding="utf-8"?>
    <BlockList>
      ${ff}
    </BlockList>`,
  )
    .progress((re, t) => console.log({re}, {t}))
    .catch(error => console.log({error}));
  console.log({res2});
};

问题根源分析

  1. 块ID重复导致覆盖
    循环中每次用new Date().toISOString()生成块ID,但循环执行速度极快,两次生成的时间戳可能完全一致,导致两个块使用同一个ID。后上传的块会覆盖先上传的,最终实际只有一个有效块。

  2. 视频块路径与文件信息获取顺序颠倒
    循环里先执行ReactNativeBlobUtil.fs.stat(videoChunks[i]),但此时videoChunks[i]还未被赋值(后续才执行videoChunks.push(chunkPath)),这会导致获取的文件大小错误,甚至读取不存在的文件,造成上传内容异常。

  3. 块列表XML格式拼接错误
    处理blockList时,用toString().replace(',', '\n')只能替换第一个逗号,多块场景下剩余逗号会保留,导致XML格式不规范。虽然查询块列表显示两个块,但实际提交的XML可能未被正确解析。

  4. 提交块列表的Content-Type错误
    提交块列表时,content-type设置为text/plain; charset=UTF-8,但Azure要求该接口的Content-Type必须是application/xml,格式不匹配可能导致解析异常。

修复建议

  • 生成唯一块ID:给时间戳追加循环索引,确保每个块ID唯一,比如:
    let dataString = encodeURIComponent(encode(`${new Date().toISOString()}_${i}`));
    
  • 调整代码执行顺序:先生成视频块路径并加入数组,再获取文件信息:
    let chunkPath = i < 10 ? `${chunks?.url}00${i}.${chunks?.ext}` : i < 100 ? `${chunks?.url}0${i}.${chunks?.ext}` : `${chunks?.url}${i}.${chunks?.ext}`;
    videoChunks.push(chunkPath);
    let info = await ReactNativeBlobUtil.fs.stat(videoChunks[i]);
    
  • 正确拼接XML内容:用join('\n')直接拼接数组元素,避免替换不彻底:
    let ff = blockList.join('\n');
    
  • 修正Content-Type:提交块列表时,将请求头的content-type改为application/xml。

内容的提问来源于stack exchange,提问作者BeginnerProgrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:32:41