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

C++客户端与Cloudflare Worker SHA-1校验和不匹配问题排查

问题

我正尝试从嵌入式设备向Cloudflare上传文件。C++应用在上传前生成SHA-1校验和,代码如下:

std::string generate_checksum(const std::string& file_path) {
    std::string test_file_path = file_path;

    std::ifstream file(test_file_path, std::ios::binary);

    if (!file) {
        throw std::runtime_error("Cannot open file for checksum.");
    }

    SHA_CTX sha1;
    SHA1_Init(&sha1);
    
    char buffer[8192];
    while (file.read(buffer, sizeof(buffer))) {
        SHA1_Update(&sha1, buffer, file.gcount());
    }

    unsigned char hash[SHA_DIGEST_LENGTH];
    SHA1_Final(hash, &sha1);

    std::ostringstream result;
    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
        result << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
    }
    
    return result.str();
}

生成的校验和存入数据库后启动上传,使用标准CURL设置。Cloudflare Worker处理上传时,将上传文件的校验和与数据库值对比,代码如下:

async function validateChecksum(fileContent, expectedChecksum) {
  const sha1Buffer = await crypto.subtle.digest("SHA-1", fileContent);
  const sha1Array = Array.from(new Uint8Array(sha1Buffer));
  const computedChecksum = sha1Array.map(b => b.toString(16).padStart(2, '0')).join('');

  return computedChecksum === expectedChecksum;
}

// handle upload method ...

    const url = new URL(request.url);
    const checksum = url.searchParams.get('checksum');

    const uploadStream = await request.body;
    const originalFileName = request.headers.get('X-Original-File-Name');

    const uploadResponse = await env.STREAM_BUCKET.put(`some-folder/${originalFileName}`, uploadStream);

    if (!uploadResponse) {
      await updateTransferStatus(site_id, camera_id, "FAILURE", env);
      
      return new Response(
        JSON.stringify({ transfer_status: "FAILURE" }), 
        { status: 500, headers: { 'Content-Type': 'application/json' } }
      );
    }

    const uploadedFile = await env.STREAM_BUCKET.get(`${site_id}/${camera_id}/${originalFileName}`);
    const fileContent = await uploadedFile.arrayBuffer();
    const isChecksumValid = await validateChecksum(fileContent, checksum);

文件完整性良好,可下载打开,文件名一致,但校验和不匹配,请问我遗漏了哪些要点?

排查要点
  • C++端文件读取不完整:原C++代码的while循环会在读取到文件末尾(剩余字节不足8192)时直接退出,导致最后一段数据未被纳入SHA-1计算。需在循环结束后补充处理剩余字节:

    while (file.read(buffer, sizeof(buffer))) {
        SHA1_Update(&sha1, buffer, file.gcount());
    }
    // 处理最后一次未填满buffer的读取内容
    if (file.gcount() > 0) {
        SHA1_Update(&sha1, buffer, file.gcount());
    }
    
  • Cloudflare存储路径不匹配:Worker中上传路径是some-folder/${originalFileName},但读取路径是${site_id}/${camera_id}/${originalFileName},两者不一致,导致读取的并非刚上传的目标文件,校验自然不匹配。需统一上传和读取的路径。

  • 校验和大小写差异:C的std::hex默认输出小写十六进制字符,JavaScript的toString(16)同样输出小写,但需确认数据库存储、URL传输过程中是否存在大小写转换(比如被转成大写)。可在两边统一转成大写/小写后再对比,比如C添加std::uppercase,或JS中用.toUpperCase()。

  • CURL上传模式问题:嵌入式环境的旧版CURL可能未默认启用二进制传输,需显式设置CURLOPT_BINARYTRANSFER,避免文本模式下的换行符转换(如CRLF转LF),导致上传文件内容与本地文件不一致。

  • 校验和传输编码问题:检查URL参数中的checksum是否被意外URL编码(如包含%字符时),Worker的searchParams.get会自动解码,若数据库存储的是原始值,可能导致对比失败。可在Worker中打印两个校验和的具体值,直接对比差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:52:47