亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 go 將 UploadPart S3 操作從傳入請求流式傳輸到 AWS S3?

如何使用 go 將 UploadPart S3 操作從傳入請求流式傳輸到 AWS S3?

Go
aluckdog 2022-08-30 22:05:07
上下文與我的團隊一起,我們正在構建一個反向代理來攔截對S3的所有傳出請求,以便審核和控制來自不同應用程序的訪問。我們通過流式傳輸文件內容,成功實現了幾乎所有操作。例如,為了使用單個操作上傳,我們使用將傳入請求的正文(這是一個)流式傳輸到S3并下載(單部分和多部分風格),我們使用原語從(這是一個)寫入響應。s3manager.Uploaderio.Readerio.Copys3.GetObjectOutput.Bodyio.ReadCloser問題:我們仍然無法通過流式處理實現的唯一操作是上傳部分(在分段上傳的上下文中)。問題是需要一個 和 來傳遞傳入請求的正文,你需要在某個位置(例如,在內存中)緩沖它。s3.UploadPartInputaws.ReadSeekCloser這就是我們到目前為止所擁有的:func (ph *VaultProxyHandler) HandleUploadPart(w http.ResponseWriter, r *http.Request, s3api s3iface.S3API, bucket string, key string, uploadID string, part int64) {    buf := bytes.NewBuffer(nil)        // here loads the entire body to memory    if _, err := io.Copy(buf, r.Body); err != nil {        http.Error(w, err.Error(), http.StatusInternalServerError)        return    }    payload := buf.Bytes()    input := &s3.UploadPartInput{        Bucket:     aws.String(bucket),        Key:        aws.String(key),        UploadId:   aws.String(uploadID),        PartNumber: aws.Int64(part),        Body:       aws.ReadSeekCloser(bytes.NewReader(payload)),    }    output, err := s3api.UploadPart(input)    // and so on...}問題:有沒有辦法將 的傳入請求流式傳輸到 S3?(我的意思是不要將整個身體存儲在內存中)。UploadPart
查看完整描述

1 回答

?
jeck貓

TA貢獻1909條經驗 獲得超7個贊

最后,我得到了一種方法,通過使用 AWS 開發工具包構建請求并使用未簽名的有效負載對其進行簽名,通過流處理反向代理傳入的 UploadPart。


下面是一個基本示例:


type AwsService struct {

    Region   string

    S3Client s3iface.S3API

    Signer   *v4.Signer

}


func NewAwsService(region string, accessKey string, secretKey string, sessionToken string) (*AwsService, error) {

    creds := credentials.NewStaticCredentials(accessKey, secretKey, sessionToken)

    awsConfig := aws.NewConfig().

        WithRegion(region).

        WithCredentials(creds).

        WithCredentialsChainVerboseErrors(true)

    sess, err := session.NewSession(awsConfig)

    if err != nil {

        return nil, err

    }

    svc := s3.New(sess)


    signer := v4.NewSigner(creds)

    v4.WithUnsignedPayload(signer)


    return &AwsService{

        Region:   region,

        S3Client: svc,

        Signer:   signer,

    }, nil

}


func (s *AwsService) UploadPart(bucket string, key string, part int, uploadID string, payloadReader io.Reader, contentLength int64) (string, error) {


    input := &s3.UploadPartInput{

        Bucket:        aws.String(bucket),

        Key:           aws.String(key),

        UploadId:      aws.String(uploadID),

        PartNumber:    aws.Int64(int64(part)),

        ContentLength: aws.Int64(contentLength),

        Body:          aws.ReadSeekCloser(payloadReader),

    }


    req, output := s.S3Client.UploadPartRequest(input)


    _, err := s.Signer.Sign(req.HTTPRequest, req.Body, s3.ServiceName, s.Region, time.Now())

    err = req.Send()

    if err != nil {

        return "", err

    }


    return *output.ETag, nil

}

然后,可以從處理程序調用它:


func HandleUploadPart(w http.ResponseWriter, r *http.Request) {


    query := r.URL.Query()

    region := query.Get("region")

    bucket := query.Get("bucket")

    key := query.Get("key")

    part, err := strconv.Atoi(query.Get("part"))

    if err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }

    uploadID := query.Get("upload-id")

    payloadReader := r.Body


    contentLength, err := strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64)

    if err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }


    etag, err := awsService.UploadPart(region, bucket, key, part, uploadID, payloadReader, contentLength)

    if err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }


    w.Header().Set("ETag", etag)

}

缺點:


客戶端必須提前知道內容長度并發送。

無法對有效負載進行簽名。


查看完整回答
反對 回復 2022-08-30
  • 1 回答
  • 0 關注
  • 250 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號