azure - 使用 go - azure 上传 blob

标签 azure go azure-blob-storage multipartform-data go-gin

我正在构建一个用 go 和 gin 编写的 API,它将 blob 上传到 Azure 存储。这是代码:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "net/url"

    "github.com/Azure/azure-storage-blob-go/azblob"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    router.POST("/upload", func(c *gin.Context) {
        accountName := "blablabla"
        accountKey := "mykey"
        containerName := "testblabla"
        blobName := c.PostForm("blobName")

        credential, err := azblob.NewSharedKeyCredential(accountName, accountKey)
        if err != nil {
            log.Fatal("Erro ao realizar nova conexão com azure", err)
            return
        } else {
            fmt.Println("Sucesso ao se conectar com o azure")
        }

        u, err := url.Parse(fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", accountName, containerName, blobName))
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "Erro ao ler URL do container": err,
            })
            log.Fatal("Erro ao ler URL do container", err)
            return
        } else {
            fmt.Println("Sucesso ao ler URL do container, eu passei por aqui")
            c.JSON(200, gin.H{
                "Sucesso ao ler URL do container": "Eu passei por aqui",
            })
        }
        blobURL := azblob.NewBlockBlobURL(*u, azblob.NewPipeline(credential, azblob.PipelineOptions{}))
        c.JSON(200, gin.H{
            "Sucesso ao ler URL do container": "Próximo passo",
        })
        log.Println("Sucesso ao ler URL do container")

        form, err := c.MultipartForm()
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "Erro ao ler arquivo": err.Error(),
            })
            log.Println("Erro ao ler arquivo", err)
            return
        }

        files := form.File["upload"]
        if len(files) == 0 {
            c.JSON(http.StatusBadRequest, gin.H{
                "Erro ao enviar arquivo para container": "Nenhum arquivo enviado",
            })
            log.Println("Nenhum arquivo enviado", err)
            return
        }

        file := files[0]

        fmt.Println("eu passei por files", file)

        log.Println(file.Filename)

        src, err := file.Open()
        if err != nil {
            c.JSON(500, gin.H{
                "Erro ao abrir arquivo": err,
            })
            log.Fatal("Erro ao abrir arquivo", err)
            return
        } else {
            fmt.Println("Sucesso ao abrir arquivo")
            c.JSON(200, gin.H{
                "Sucesso ao abrir arquivo": "Proximo passo",
            })
        }

        options := azblob.UploadStreamToBlockBlobOptions{
            MaxBuffers: 3,
        }
        _, err = azblob.UploadStreamToBlockBlob(context.Background(), src, blobURL, options)

        if err != nil {
            fmt.Println("deu erro, mas passei por aqui")
            c.JSON(http.StatusInternalServerError, "Deu erro, mas passei aqui")
            c.JSON(http.StatusInternalServerError, gin.H{
                "Erro ao enviar arquivo para container": err.Error(),
            })
            log.Println("Erro ao enviar arquivo para container", err)
            return
        } else {
            c.JSON(http.StatusOK, gin.H{
                "message": "Arquivo enviado com sucesso!",
            })
            fmt.Println("Sucesso ao enviar arquivo")

        }
    })
    router.Run(":8080")
}

以下是使用 Postman 测试此 API 的步骤:

  1. 选择POST作为方法
  2. 输入 API 的 URL
  3. 选择正文选项卡下的表单数据
  4. 列中,我输入 blob 的名称,然后选择类型文件,然后选择我的文件
  5. 发送请求

我收到此错误:

Erro ao enviar arquivo para container write error: -> github.com/Azure/azure-storage-blob-go/azblob.newStorageError, C:/Users/rodri/go/pkg/mod/github.com/!azure/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1978636c6b7c346a6d766b787e7c347b75767b347e76596f2937282c3729" rel="noreferrer noopener nofollow">[email protected]</a>/azblob/zc_storage_error.go:42
===== RESPONSE ERROR (ServiceCode=InvalidUri) =====
Description=The requested URI does not represent any resource on the server.
RequestId:a31b34a1-401e-000c-3aa8-6fb698000000
Time:2023-04-15T14:43:41.9699330Z, Details:
   Code: InvalidUri
   UriPath: https://blablabla.blob.core.windows.net/teste/?blockid=mLa1s8Y9Tu6Tqw0umZ2kiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==&comp=block&timeout=61        
   PUT https://blablabla.blob.core.windows.net/teste/?blockid=mLa1s8Y9Tu6Tqw0umZ2kiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%3D%3D&comp=block&timeout=61
   Authorization: REDACTED
   Content-Length: [5]
   User-Agent: [Azure-Storage/0.15 (go1.20; Windows_NT)]
   X-Ms-Client-Request-Id: [5e531a97-f854-476c-49f7-407a29468e89]
   X-Ms-Date: [Sat, 15 Apr 2023 14:43:41 GMT]
   X-Ms-Version: [2020-10-02]
   --------------------------------------------------------------------------------
   RESPONSE Status: 400 The requested URI does not represent any resource on the server.      
   Content-Length: [438]
   Content-Type: [application/xml]
   Date: [Sat, 15 Apr 2023 14:43:41 GMT]
   Server: [Microsoft-HTTPAPI/2.0]
   X-Ms-Error-Code: [InvalidUri]
   X-Ms-Request-Id: [a31b34a1-401e-000c-3aa8-6fb698000000]

为什么?

最佳答案

出了什么问题?

请求中没有名为 blobName 的表单字段。

blobName := c.PostForm("blobName")

证据

错误消息对此很清楚:

Code: InvalidUri
UriPath: https://blablabla.blob.core.windows.net/teste/?blockid=mLa1s8Y9Tu6Tqw0umZ2kiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==&comp=block&timeout=61
                                                      ^^^

比较

fmt.Sprintf("https://%s.blob.core.windows.net/%s/%s", accountName, containerName, blobName)
                                                 ^^^

很明显blobName是空的。

说明

此 postman 请求

Postman UI: adding key "blobName"

原始 HTTP 请求看起来像这样:

POST /anything HTTP/1.1
Host: httpbin.org
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeobf4rJjB8V8AYfS
 
----WebKitFormBoundaryeobf4rJjB8V8AYfS
Content-Disposition: form-data; name="upload"; filename="sample.pdf"

<content omitted>
----WebKitFormBoundaryeobf4rJjB8V8AYfS
Content-Disposition: form-data; name="blobName"
myBlobName
----WebKitFormBoundaryeobf4rJjB8V8AYfS

如果此类请求由您的处理程序处理,

  • blobName := c.PostForm("blobName") 将是 myBlobName
  • 文件 := form.File["上传"]; file := files[0] 获取描述上传文件的文件头
  • file.Filename 将是 sample.pdf

关于azure - 使用 go - azure 上传 blob,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76023001/

相关文章:

go - 如何使用 Go 获取大查询中的表列名称列表

c# - 列出 Windows Azure Blob 存储容器中的 EMPTY 目录

azure - 从本地 MySQL 提取数据并将其转换到 Azure Synapse 数据仓库

azure - 如何在 Azure PaaS 上的 Tomcat 中扩展 ErrorReportValve?

go - 为什么在只有3个实体的 map 上创建的数组中有6个条目?

go - 创建 map[string]struct{} 并赋值

azure - 将 Azure 虚拟机本地文件夹备份到 Blob 存储?

c# - Azure WebJobs Blob 触发器 - 多次调整大小

c# - 提高 Azure Blob 存储查询速度

azure - 我需要通过用户身份验证连接到 Azure 媒体服务