如何通过AWS Lambda和GoLang中的API Gateway将二进制文件上传和下载到AWS S3?

h9a6wy2h  于 2023-02-27  发布在  Go
关注(0)|答案(1)|浏览(266)

使用AWS Lambda服务API调用会带来很多警告和限制,包括通过AWS API Gateway集成代理服务器的限制,其中一个是负载大小限制,另一个是负载编码困难,无论是二进制、文本或JSON,还是二进制-无论是二进制blob(字节)还是base64编码字符串。

jogvjijk

jogvjijk1#

为了让文件往返于API网关-〉Lambda -〉S3和S3 -〉Lambda -〉API网关之间,您必须配置POSTMAN、API网关、Lambda、和本地代码来处理base64编码的有效负载。这是API Gateway转换二进制blob有效负载的一种方式。here有多种定义方式,但以下示例是最简单的:

步骤0 -配置

1.您将需要为您想要用来处理二进制文件的每个API网关启用二进制编码类型。
1.导航至AWS控制台-〉API网关-〉选择您的API -〉设置-〉二进制媒体类型
1.添加*/*
1.单击“保存更改”或更新IAC以修改API网关。使用无服务器框架,您可以执行以下操作:
serverless.yml

provider:
  apiGateway:
    binaryMediaTypes:
      - '*/*'

第一步-透过POSTMAN上载

  1. x1米2英寸x1米3英寸
  2. Headers.Content-Type应为multipart/form-data; boundary=<calculated when request is sent>
  3. Headers.Content-Length应为<calculated when request is sent>
    1.在Body下选择form-data,在key下输入filename,输入filevalue作为选择的二进制文件上传。PDF是一个很好的工作示例。

步骤2 - 1上传Lambda处理程序功能

func UploadLambda(ctx context.Context, lambdaReq events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    if !lambdaReq.IsBase64Encoded {
        return ...
    }

    fileHeaders, err := GetHeaders(lambdaReq, MaxFileSizeBytes)
    if err != nil {
        return ...
    }

    if len(fileHeaders) != 1 {
        return ...
    }

    fileName := uuid.New().String()
    fileExtension := path.Ext(fileHeaders[0].Filename)
    fileName = fileName + fileExtension

    // take the first file uploaded via HTTP and upload it to S3
    uploadResult, err := UploadHeader(fileHeaders[0], os.Getenv("REGION"), os.Getenv("BUCKET"), fileName)
    if err != nil {
         return...
    }

    return events.APIGatewayProxyResponse{Status: 200}, nil
}

步骤2 - 2解析Lambda函数的标头

func GetHeaders(lambdaReq events.APIGatewayProxyRequest, maxFileSizeBytes int64) ([]*multipart.FileHeader, error) {
    // https://github.com/aws/aws-lambda-go/issues/117
    headers := http.Header{}

    for header, values := range lambdaReq.Headers {
        headers.Add(header, values)
    }

    contentType := headers.Get("Content-Type")
    if contentType == "" {
        return...
    }

    _, params, err := mime.ParseMediaType(contentType)
    if err != nil {
        return...
    }

    boundary := params["boundary"]
    if boundary == "" {
        return...
    }

    stringReader := strings.NewReader(lambdaReq.Body) 
    b64Reader := base64.NewDecoder(base64.StdEncoding, stringReader)
    multipartReader := multipart.NewReader(b64Reader, boundary)

    form, err := multipartReader.ReadForm(maxFileSizeBytes)
    if err != nil {
        return...
    }

    var files []*multipart.FileHeader

    for currentFileName := range form.File {
        files = append(files, form.File[currentFileName][0])
    }

    return files, nil
}

第2 - 3步上传到S3功能

func UploadHeader(fileHeader *multipart.FileHeader, region, bucket, name string) (*UploadRes, error) {

    file, err := fileHeader.Open()
    if err != nil {
        return...
    }

    var fileContents []byte
    _, err = file.Read(fileContents)
    if err != nil {
        return...
    }

    awsSession, err := session.NewSession(&aws.Config{
        Region: aws.String(region)},
    )
    if err != nil {
        return...
    }

    uploader := s3manager.NewUploader(awsSession)

    uploadOutput, err := uploader.Upload(&s3manager.UploadInput{
        Bucket: aws.String(bucket),
        Key:    aws.String(name),
        Body:   file,
    })
    if err != nil {
        return...
    }

    return &UploadRes{
        S3Path: filepath.Join(bucket, name),
        S3URL:  uploadOutput.Location,
    }, nil
}

步骤3 - 1下载Lambda处理程序函数

func DownloadLambda(ctx context.Context, lambdaReq events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    file := Get(...)

    fileBytes, err := Download(os.Getenv("REGION"), os.Getenv("BUCKET"), file.Name)
    if err != nil {
        return...
    }

    return FileB64Res(file.ContentType, nil, fileBytes)
}

步骤3 - 2下载S3功能

func Download(region, bucket, name string) ([]byte, error) {
    awsSession, err := session.NewSession(&aws.Config{
        Region: aws.String(region)},
    )
    if err != nil {
        return...
    }

    downloader := s3manager.NewDownloader(awsSession)

    var fileBytes []byte
    writeAtBuffer := aws.NewWriteAtBuffer(fileBytes)

    getObjectInput := &s3.GetObjectInput{
        Bucket: aws.String(bucket),
        Key:    aws.String(name),
    }

    // functional options pattern
    bytesDownloaded, err := downloader.Download(writeAtBuffer, getObjectInput, func(downloader *s3manager.Downloader) {
        downloader.Concurrency = 0
    })
    if err != nil {
        return...
    }

    if bytesDownloaded == 0 {
        return...
    }

    return writeAtBuffer.Bytes(), nil
}

func FileB64Res(contentType string, headers map[string]string, fileBytes []byte) (events.APIGatewayProxyResponse, error) {
    if headers == nil {
        headers = map[string]string{
            ContentTypeKey: contentType,
        }
    } else {
        headers[ContentTypeKey] = contentType
    }

    return events.APIGatewayProxyResponse{
        StatusCode:      http.StatusOK,
        Headers:         headers,
        Body:            base64.StdEncoding.EncodeToString(fileBytes),
        IsBase64Encoded: true,
    }, nil
}

步骤4 - 1透过 Postman 下载

  1. x一米十三英寸x一米十四英寸
    1.将Headers.Accept设置为*/*
    1.当POSTMAN中的Body的“预览”呈现PDF或图像时,您将知道一切都正常工作。如果您没有预览-当从bytes(postman)-〉b64 string(api网关)-〉bytes(S3存储)-〉b64 string(api网关)-〉bytes(postman)转换时,字节仍然会损坏。
    这绝对是您在GoLang for AWS Lambda中使用API Gateway作为代理处理二进制有效载荷所需的一切。从POSTMAN迁移到浏览器时,不要忘记CORS!

相关问题