【问题标题】:Getting Bad Request 400 Errors Trying to Upload File to Google Cloud Storage Using A Generated MD5 or CRC32C Checksum for the File尝试使用为文件生成的 MD5 或 CRC32C 校验和将文件上传到 Google 云存储时遇到错误请求 400 错误
【发布时间】:2018-06-07 16:17:09
【问题描述】:

我正在尝试使用 Google Cloud Storage Java API 将文件上传到 Google Cloud Storage,并在上传前为文件设置 md5 或 crc32c 校验和/哈希。

我不断收到类似于下面显示的错误(对于 md5 和 crc32c 哈希)并且不知道我做错了什么:

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "invalid",
    "message": "Provided CRC32C \"qtQiXA==\" doesn't match calculated CRC32C \"AAAAAA==\"."
   }
  ],
  "code": 400,
  "message": "Provided CRC32C \"qtQiXA==\" doesn't match calculated CRC32C \"AAAAAA==\"."
 }
}

如果没有在 BlobInfo 上设置 md5 或 crc32c 校验和值,则文件上传有效。我在使用 WriteChannel 上传文件 blob 之前尝试实现的代码 sn-p 如下所示:

// Upload a blob to the identified bucket and use md5 or crc32c checksum 
BlobId blobId = BlobId.of(storageBucketName, sourceEvent.getFileName());
BlobInfo blobInfo = null;
Storage.BlobWriteOption blobWriteOption = null;

if(sourceEvent.getFileHash() != null && sourceEvent.getFileHashType() == FileIntegrityCheckType.CRC32C.getCheckType()) {
    blobInfo = BlobInfo.newBuilder(blobId).setStorageClass(
            GoogleCloudStorageClass.getStorageClass(storageClass)
    ).setCrc32c(sourceEvent.getFileHash()).build();
    blobWriteOption = Storage.BlobWriteOption.crc32cMatch();
} else if(sourceEvent.getFileHash() != null && sourceEvent.getFileHashType() == FileIntegrityCheckType.MD5.getCheckType()) {
    blobInfo = BlobInfo.newBuilder(blobId).setStorageClass(
            GoogleCloudStorageClass.getStorageClass(storageClass)
    ).setMd5(sourceEvent.getFileHash()).build();
    blobWriteOption = Storage.BlobWriteOption.md5Match();
} else {
    blobInfo = BlobInfo.newBuilder(blobId).setStorageClass(
            GoogleCloudStorageClass.getStorageClass(storageClass)).build();
}

下面列出了我使用 Google Guava Hashing API 生成文件 crc32c 和 md5 哈希的方法:

    private byte[] generateCrc32CheckSum(Path file) {
        byte[] crc32CheckSum = new byte[0];

        if(file != null) {
            byte[] buffer = new byte[SysConstants.FILE_READ_BUFFER_SIZE];
            int limit = -1;
            HashFunction crc32cHashFunc = Hashing.crc32c();
            Hasher crc32cHasher = crc32cHashFunc.newHasher();

            try (FileInputStream fis = new FileInputStream(file.toFile())) {
                while ((limit = fis.read(buffer)) > 0) {
                    crc32cHasher.putBytes(buffer, 0, limit);
                }

//                    crc32CheckSum = crc32cHasher.hash().asBytes();
                crc32CheckSum = Ints.toByteArray(crc32cHasher.hash().asInt());

            } catch (IOException e) {
                e.printStackTrace(); 
            }
        }

        return crc32CheckSum;
    }

    private byte[] generateMd5Hash(Path file) {
        byte[] md5Hash = new byte[0];

        if(file != null) {
            byte[] buffer = new byte[SysConstants.FILE_READ_BUFFER_SIZE];
            int limit = -1;
            HashFunction md5HashFunc = Hashing.md5();
            Hasher md5Hasher = md5HashFunc.newHasher();

            try (FileInputStream fis = new FileInputStream(file.toFile())) {
                while ((limit = fis.read(buffer)) > 0) {
                    md5Hasher.putBytes(buffer, 0, limit);
                }

                md5Hash = md5Hasher.hash().asBytes();

            } catch (IOException e) {
                e.printStackTrace();            
            }
        }

        return md5Hash;
    }

然后我用下面的方法做Base64编码:

public void queueFileWithSizeAndIntegrityCheckToken(SourceEvent sourceEvent, FileTransferStatus queuedStatus) {
    if(isFileTransferReady(sourceEvent)) {
        String fileName = sourceEvent.getFileName();
        Path filePath = Paths.get(fileName);

        if(filePath != null) {
            long fileSize = filePath.toFile().length();

            if(fileSize > 0) {
                sourceEvent.setFileSize(fileSize);

                if (isIntegrityCheckEnabled) {
                    if (integrityCheckType.equalsIgnoreCase(FileIntegrityCheckType.CRC32C.getIntegrityCheckTokenType())) {
                        byte[] crc32CheckSum = generateCrc32CheckSum(filePath);

                        if(crc32CheckSum.length > 0) {
                            sourceEvent.setFileHash(BaseEncoding.base64().encode(crc32CheckSum));
                            sourceEvent.setFileHashType(FileIntegrityCheckType.CRC32C.getCheckType());
                        }
                    } else if (integrityCheckType.equalsIgnoreCase(FileIntegrityCheckType.MD5.getIntegrityCheckTokenType())) {
                        byte[] md5Token = generateMd5Hash(filePath);

                        if(md5Token.length > 0) {
                            sourceEvent.setFileHash(BaseEncoding.base64().encode(md5Token));
                            sourceEvent.setFileHashType(FileIntegrityCheckType.MD5.getCheckType());
                        }
                    }
                }

                fileTransferLogService.updateSourceEventStatus(sourceEvent,
                        queuedStatus);
            }
        }
    }
}

有人可以检查并告诉我我做错了什么吗?谢谢。

【问题讨论】:

  • 不是答案,但AAAAAA== 是空文件的CRC32C。这有帮助吗?我的意思是,还有什么会导致您上传空文件吗?
  • 我怀疑我上传的是一个空文件。如果我没有在 BlobInfo 对象上设置 crc32c 或 md5 哈希,则文件会正常上传。我只有在设置这些哈希类型和值时才会遇到问题。

标签: google-cloud-storage


【解决方案1】:

上述代码有效,Google Cloud Storage 服务或 Google Cloud Storage Java 客户端库没有问题。

问题已解决,似乎是由 Spring 中的事务设置引起的,这显然影响了要上传的文件的正确处理以及所需 crc32c 和 md5 哈希值的生成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 2021-02-11
    • 2021-10-15
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多