使用 REST API 上传到 Azure Blob 存储时,Zip 档案损坏

Posted

技术标签:

【中文标题】使用 REST API 上传到 Azure Blob 存储时,Zip 档案损坏【英文标题】:Zip Archives get corrupted when uploading to Azure Blob Store using REST API 【发布时间】:2021-11-04 15:27:52 【问题描述】:

我一直在用这个把头撞到墙上,上传文本文件很好,但是当我将 zip 存档上传到我的 blob 存储时 -> 它已损坏,下载后无法打开。 对通过 Azure 的原始文件与文件进行十六进制比较(下图)显示发生了一些微妙的替换,但我找不到更改/损坏的来源。 我曾尝试强制使用 UTF-8/Ascii/UTF-16,但发现 UTF-8 可能是正确的,没有解决问题。 我也尝试了不同的 http 库,但得到了相同的结果。 部署环境强制 unirest,并且无法使用 Microsoft API(这似乎工作正常)。

package blobQuickstart.blobAzureApp;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Base64;
import org.junit.Test;

import kong.unirest.HttpResponse;
import kong.unirest.Unirest;

public class ***Example 

    @Test
    public void uploadSmallZip() throws Exception 

        File testFile = new File("src/test/resources/zip/simple.zip");
        String blobStore = "secretstore";

        UploadedFile testUploadedFile = new UploadedFile();
        testUploadedFile.setName(testFile.getName());
        testUploadedFile.setFile(testFile);

        String contentType = "application/zip";

        String body = readFileContent(testFile);
        String url = "https://" + blobStore + ".blob.core.windows.net/naratest/" + testFile.getName() + "?sv=2020-02-10&ss=b&srt=o&sp=c&se=2021-09-07T20%3A10%3A50Z&st=2021-09-07T18%3A10%3A50Z&spr=https&sig=xvQTkCQcfMTwWSP5gXeTB5vHlCh2oZXvmvL3kaXRWQg%3D";

        HttpResponse<String> response = Unirest.put(url)
                .header("x-ms-blob-type", "BlockBlob").header("Content-Type", contentType)
                .body(body).asString();

        if (!response.isSuccess()) 
            System.out.println(response.getBody());
            throw new Exception("Failed to Upload File! Unexpected response code: " + response.getStatus());
        
    

    private static String readFileContent(File file) throws Exception 

        InputStream is = new FileInputStream(file);

        ByteArrayOutputStream answer = new ByteArrayOutputStream();
        byte[] byteBuffer = new byte[8192];    
        int nbByteRead;    

        while ((nbByteRead = is.read(byteBuffer)) != -1) 
                      
            answer.write(byteBuffer, 0, nbByteRead);        
                
        is.close();    

        byte[] fileContents = answer.toByteArray();
        String s = Base64.getEncoder().encodeToString(fileContents);
        byte[] resultBytes = Base64.getDecoder().decode(s);
        String encodedContents = new String(resultBytes);
        return encodedContents;
    

请帮忙!

【问题讨论】:

【参考方案1】:
    byte[] resultBytes = Base64.getDecoder().decode(s);
    String encodedContents = new String(resultBytes);

您正在从包含二进制数据的字节数组创建字符串。字符串仅用于可打印字符。您进行多次无意义的编码/解码只是占用更多内存。

如果内容为 ZIP 格式,则为二进制,返回字节数组即可。或者您可以对内容进行编码,但您应该返回已编码的内容。作为一个弱点,你在内存中做这一切,限制了内容的潜在大小。

【讨论】:

感谢您的回答,如果我知道 Unirest 可以直接处理一个字节 [],我会早点尝试,最终我在这里找到了正确的语法:github.com/Kong/unirest-java/issues/248【参考方案2】:

Unirest 文件处理程序将默认强制使用多部分正文 - Azure 不支持。

可以直接提供一个字节数组,如下:https://github.com/Kong/unirest-java/issues/248

Unirest.put("http://somewhere")
                .body("abc".getBytes())

【讨论】:

以上是关于使用 REST API 上传到 Azure Blob 存储时,Zip 档案损坏的主要内容,如果未能解决你的问题,请参考以下文章

Django rest 框架 - 将图像上传到 Azure 存储

Azure 数据工厂使用 REST Multipart/form-data 上传文件

在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储

如何使用REST API将文件存储卷安装到azure容器实例

如何将 azure 广告集成到在 azure 中也使用 REST API 的 React Web 应用程序

REST Api 使用访问密钥到 Azure Blob 存储