// 创建一个新的 MD5 哈希计算器
hasher2 := md5.New()
// 将文件流复制到哈希计算器中
_, err = io.Copy(hasher2, object)
if err != nil {
        return "", fmt.Errorf("error calculating MD5: %v", err)
}
// 返回 MD5 值的十六进制字符串
videoSignature2 := hex.EncodeToString(hasher2.Sum(nil))  
   
//对比下面的代码
//创建一个 MD5 哈希计算器
hasher := md5.New()

// 使用 TeeReader 同时计算 MD5 并将文件流传给 TikTok
teeReader := io.TeeReader(object, hasher)

// 计算 MD5 的同时,将文件上传到 TikTok
videoSignature := hex.EncodeToString(hasher.Sum(nil))  
//计算的md5秘钥不一样 
在提供的两段代码中,尽管都在计算 MD5 哈希值,但计算出的 videoSignature 和 videoSignature2 可能会不同,原因在于如何处理文件流(即 object)以及哈希计算的时机。

我们来逐步分析两个代码块之间的差异,以及为什么会计算出不同的 MD5 值:
第一个代码段:使用 io.TeeReader 的方式

// 创建一个 MD5 哈希计算器
hasher := md5.New()

// 使用 TeeReader 同时计算 MD5 并将文件流传给 TikTok
teeReader := io.TeeReader(object, hasher)

// 计算 MD5 的同时,将文件上传到 TikTok
videoSignature := hex.EncodeToString(hasher.Sum(nil))

第二个代码段:直接使用 io.Copy 计算 MD5

// 创建一个新的 MD5 哈希计算器
hasher2 := md5.New()
// 将文件流复制到哈希计算器中
_, err = io.Copy(hasher2, object)
if err != nil {
    return "", fmt.Errorf("error calculating MD5: %v", err)
}
// 返回 MD5 值的十六进制字符串
videoSignature2 := hex.EncodeToString(hasher2.Sum(nil))

分析差异

文件流的消耗(流指针的偏移):
在第二段代码中,io.Copy(hasher2, object) 会消耗 object 流。即,读取文件流的同时计算 MD5 后,object 流指针已经移动到了文件的末尾。如果你在之后的上传操作中继续使用这个流,流指针已经偏移到文件的末尾,这可能导致上传内容为空。

TeeReader 的作用:
在第一段代码中,TeeReader 同时读取流并将内容传递到 hasher 进行 MD5 哈希计算,同时将内容传递到上传的目标。TeeReader 允许你在读取流的时候,不影响原始流的指针位置,从而确保上传操作不受影响。object 流的内容被读取并上传,而 MD5 的计算仍然有效。
重要的是,teeReader 只是在读取数据的同时将数据传递给 hasher,并不消耗流中的内容。它只是将数据传递给两个目标:一个是 MD5 哈希计算器,另一个是上传操作。

hasher.Sum(nil) 的位置:在第一段代码中,hasher.Sum(nil) 被调用时,TeeReader 还没有完全读取文件流,因此 MD5 值实际上是在文件流完全被读取之后才计算出来的。

在第二段代码中,hasher2.Sum(nil) 被调用时,io.Copy 已经读取并消耗了文件流。所以,文件流指针已经移动到了文件末尾。

关键问题:文件流的偏移
由于在第二段代码中,object 流已经被消耗,所以它指向文件末尾,而 MD5 值计算也已完成。再调用 object 时,会出现流已经没有数据的情况。

而在第一段代码中,TeeReader 解决了这个问题,确保了文件流能够同时进行 MD5 哈希计算和上传操作,且不改变文件流指针的位置。

如何确保 MD5 哈希值一致?
确保流指针没有偏移:如果你想确保 MD5 值计算的一致性,最好使用 TeeReader 或者下载文件并缓存,然后分别计算 MD5 和上传。这样可以避免流指针的偏移。

避免多次读取同一流:计算 MD5 和上传操作尽量不要共享同一文件流。如果使用 io.Copy,确保在每次使用前重置文件流的指针位置,或者使用类似 TeeReader 这样的工具,保证文件流既用于计算 MD5,又用于上传。

修正代码:保持一致性
如果你希望使用 TeeReader 且同时计算 MD5 和上传,可以尝试如下方式:

// 创建一个 MD5 哈希计算器
hasher := md5.New()

// 使用 TeeReader 同时计算 MD5 并将文件流传给 TikTok
teeReader := io.TeeReader(object, hasher)

// 创建上传请求
formFile, err := writer.CreateFormFile("video_file", fileName)
if err != nil {
    return "", fmt.Errorf("failed to create form file: %w", err)
}

// 将文件流传给 formFile,同时计算 MD5
_, err = io.Copy(formFile, teeReader)
if err != nil {
    return "", fmt.Errorf("failed to copy file to form file: %w", err)
}

// 计算 MD5 签名
videoSignature := hex.EncodeToString(hasher.Sum(nil))

总结:
io.TeeReader 是计算 MD5 和上传文件时的最佳选择,它确保了文件流指针的不会偏移,既能计算哈希值,又能上传文件。
io.Copy 直接复制流内容到计算器时会改变流的指针,导致 MD5 值和上传文件的过程发生冲突。


叶剑飞雪
137 声望9 粉丝