我需要使用Go AWS SDK中的GetObject
系列函数从S3存储桶中获取对象,其中对象的键可能以一个或多个斜杠开头。但是,SDK似乎删除了那些前导斜杠,从而更改了密钥。
我创建了一个存储桶,并将这些数据放入:
$ aws s3 mb <TEST BUCKET>
$ aws s3 cp <SOME FILE> s3://<TEST BUCKET>//leadingslash
以下代码显示ListObjects
正确返回带有前导斜杠的键,但是在运行时,日志显示GET
请求已完成而没有前导斜杠。
package main
import (
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func main() {
bucket := "<TEST BUCKET>"
region := "<TEST BUCKET REGION>"
config := (&aws.Config{Region: ®ion}).WithLogLevel(aws.LogDebugWithHTTPBody)
s3svc := s3.New(session.New(config))
listInput := s3.ListObjectsInput{
Bucket: &bucket,
}
listOutput, err := s3svc.ListObjects(&listInput)
if err != nil {
log.Fatalf("Failed to list objects: %v", err)
} else {
log.Printf("Good: %v", listOutput)
}
for _, object := range listOutput.Contents {
getInput := s3.GetObjectInput{
Bucket: &bucket,
Key: object.Key,
}
getOutput, err := s3svc.GetObject(&getInput)
if err != nil {
log.Fatalf("Failed to HEAD object: %v", err)
} else {
log.Printf("Good: %v", getOutput)
}
}
}
启用调试日志记录的GetObject
调用显示SDK执行以下请求:
GET /leadingslash HTTP/1.1
这缺少前导斜杠并返回404错误。
我应该如何使用Go SDK获取此类对象?我无法控制对象的密钥。
在将密钥传递给GetObject
之前,我已经尝试过网址转义,但百分号会被转义并且密钥会发生变化。
我使用Go 1.9 linux / amd64和SDK 1.12.62。
答案 0 :(得分:1)
按照@ michael-sqlbot的建议,通过使用自定义逻辑来构建请求解决了这个问题:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/private/protocol/rest"
)
const (
BUCKET = "<TEST BUCKET>"
KEY = "/leadingslashkey"
REGION = "<TEST BUCKET REGION>"
)
func main() {
credentials := credentials.NewEnvCredentials()
signer := v4.NewSigner(credentials)
request, err := http.NewRequest(
http.MethodGet,
fmt.Sprintf("https://%s.s3.%s.amazonaws.com/%s", BUCKET, REGION, rest.EscapePath(KEY, false)),
nil,
)
if err != nil {
println(err.Error())
return
}
header, err := signer.Sign(
request,
nil,
"s3",
REGION,
time.Now(),
)
if err != nil {
println(err, err.Error())
return
}
fmt.Printf("%#v\n", header)
fmt.Printf("%#v\n", request)
client := http.Client{}
response, err := client.Do(request)
if err != nil {
println(err, err.Error())
return
}
fmt.Printf("%#v\n", response)
out, _ := ioutil.ReadAll(response.Body)
println(string(out))
}
答案 1 :(得分:1)
只是遇到了同样的问题,但经过一段时间的调试和调试后,我发现了另一个解决方案。
解决方案是将其添加到您的s3客户端配置中。
DisableRestProtocolURICleaning: aws.Bool(true),
来自AWS SDK for Go API Reference:
自动URI清理
与键包含相邻斜杠的对象进行交互(例如 bucketname / foo // bar / objectname)需要设置 在使用的aws.Config结构中将DisableRestProtocolURICleaning设置为true 由服务客户端。
svc := s3.New(sess, &aws.Config{
DisableRestProtocolURICleaning: aws.Bool(true),
})
out, err := svc.GetObject(&s3.GetObjectInput {
Bucket: aws.String("bucketname"),
Key: aws.String("//foo//bar//moo"),
})