使用java中的azure函数将文件从浏览器上传到azure blob存储

Posted

技术标签:

【中文标题】使用java中的azure函数将文件从浏览器上传到azure blob存储【英文标题】:Uploading file from browser to azure blob storage using azure function in java 【发布时间】:2020-01-09 16:50:56 【问题描述】:

我正在尝试通过 azure 函数将文件上传到 Azure 存储。我成功上传了纯文本文件,但是对于任何其他类型的文件,这些文件都已损坏。我观察到的是我收到的字节小于实际大小(bodyLength

我尝试将请求数据类型更改为

HttpRequestMessage>
抛出的
HttpRequestMessage 和 Byte[] 
无法转换为byte[] input broken #239[^] 中报告的字符串错误

@FunctionName("上传文件")
    公共 HttpResponseMessage 运行(@HttpTrigger(名称 = “请求”,方法 =  HttpMethod.GET,
            HttpMethod.POST , authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage(Optional(String>> request,
            最终的 ExecutionContext 上下文)
            抛出 InvalidKeyException,URISyntaxException,StorageException,IOException 

    CloudStorageAccount storageAccount = CloudStorageAccount.parse(_storageConnString);

    CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
    CloudBlobContainer blobContainer = blobClient.getContainerReference(_containerName);

    CloudBlockBlob blob = blobContainer.getBlockBlobReference(fileName);
    try 

        String body = request.getBody().get(); 
        long bodyLength = body.length();
        String contentLength = request.getHeaders().get("content-length");
        InputStream inputStream = new ByteArrayInputStream(body.getBytes());
        blob.upload(inputStream, Integer.parseInt(bodyLength));

     catch (Exception ex) 
        return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body(ex.getMessage()).build();
    

    return request.createResponseBuilder(HttpStatus.OK).body("File uploaded successfully").build();


我的要求是通过 azure 函数将大文件上传到存储。任何帮助都将不胜感激。

【问题讨论】:

【参考方案1】:

这似乎是因为您需要将原始流上传到 blob 存储。我以前用turn it to byte[]上传,但也失败了。我使用 C# 并遇到了与您相同的问题。 问题出在这个地方:

String body = request.getBody().get(); 
InputStream inputStream = new ByteArrayInputStream(body.getBytes());
blob.upload(inputStream, Integer.parseInt(bodyLength));

在 C# 中,我使用 blob.UploadFromStreamAsync(req.Body);,然后问题就消失了。你可以检查Java是否有类似的方法。

【讨论】:

我们在 java 中有 blob.uploadFromByteArray(bytes,0,bytes.length)。但它没有用。【参考方案2】:

经测试,是请求头引起的。从这个similar answer,您可以发现必须发送带有multipart/form-data 标头的正文。如果没有标题,我会得到和你一样的结果。

设置content-type标头后,长度不变。

但是即使长度相等,如果您发送的文件不是txt文件而是pdf或图像等。Java Azure Function会出现一些字节丢失的问题,这将与OP更新中的情况相同我参考的答案。

所以如果你上传其他类型的文件,解决方法是将文件转换为base64字符串发布到Function,然后在函数中转换base64字符串然后上传到blob。

byte[] scanBytes = Base64.getDecoder().decode(base64 string from request);
blob.UploadFromByteArray(scanBytes , 0, scanBytes.Length);

节点:如果你想发布大文件,你应该知道有一个最大请求大小(100MB),这是无法更改的。 Github issue。但是在本地环境中最多声明是10MB~20MB,我测试本地出现这个限制。所以最好不要发布太大的文件。

【讨论】:

@user3407500,任何进程?你能用我的功能上传文件吗?如果这可以帮助你,请接受它作为答案。【参考方案3】:

检查了the official tutorial,但遗憾的是,没有任何帮助。文档太旧了,甚至还有一些错误。

通过本地测试,我发现即使设置了正确的内容类型标头,azure java 函数也无法按预期处理不同的内容。

在大多数情况下,它会将内容视为纯文本。在大多数情况下,如果没有不可读的特殊字符,那将没有问题。

但是,对于其他文件,例如:图像文件、二进制文件和其他可能包含不可读特殊字符的文件,Azure 函数似乎只是忽略了一些不可读字符。

为了解决这个问题,您可以将请求内容类型标头设置为application/octet-stream,这意味着它是未知格式。这样,Azure 函数将保留所有内容字节。

但是,George 的方式(使用 multipart/form-data)也可以。因为如果 content-type 是 multipart/form-data,系统也会保留所有的内容(这是诀窍),这样你就可以得到每个部分都有定义的边界字符串。该方法的使用场景是以http形式上传文件。您只需将 enctype 设置为“multipart/form-data”

<FORM method="POST" action="....." enctype="multipart/form-data">
    <INPUT type="file" name="pic">
    <INPUT type="submit" value="submit" name="submit">
</FORM>

因此,如果您只想通过编程将文件发布到 Azure 函数,请将 content-type 设置为 application/octet-stream。

【讨论】:

以上是关于使用java中的azure函数将文件从浏览器上传到azure blob存储的主要内容,如果未能解决你的问题,请参考以下文章

直接从浏览器将文件上传到 Azure Blob 存储?

将文件从浏览器上传到 Azure Blob 存储,无需 SAS 密钥

如何从 azure 函数应用程序将文件发送到 azure 存储

如何将 AppendBlob/大于 4mb 限制的文件上传到 Java 中的 Azure 存储/Blob?

在 azure blob 子容器中从本地上传 zip

Azure DSC 将文件从存储上传到 VM?