Сохранение файла на S3 с помощью aws-sdk-go

У меня возникли проблемы с сохранением файла в golang с помощью AWS S3 go sdk (https://github.com/awslabs/aws-sdk-go).

Вот что у меня есть:

import (
        "fmt"
        "bytes"

        "github.com/awslabs/aws-sdk-go/aws"
        "github.com/awslabs/aws-sdk-go/aws/awsutil"
        "github.com/awslabs/aws-sdk-go/service/s3"
)

func main() {    
    cred := aws.DefaultChainCredentials
    cred.Get() // i'm using environment variable credentials and yes, I checked if they were in here
    svc := s3.New(&aws.Config{Region: "us-west-2", Credentials:cred, LogLevel: 1})
    params := &s3.PutObjectInput{
                    Bucket:         aws.String("my-bucket-123"),
                    Key:            aws.String("test/123/"),
                    Body:         bytes.NewReader([]byte("testing!")),
            }
    resp, err := svc.PutObject(params)
    fmt.Printf("response %s", awsutil.StringValue(resp))
}

Я продолжаю получать ответ 301 Moved Permanently.

Изменить: я создал ведро вручную. Изменить № 2: Пример ответа:

---[ RESPONSE ]--------------------------------------
HTTP/1.1 301 Moved Permanently
Transfer-Encoding: chunked
Content-Type: application/xml
Date: Tue, 05 May 2015 18:42:03 GMT
Server: AmazonS3

Знак POST тоже http.


person John    schedule 05.05.2015    source источник
comment
можешь выложить логи что там написано? обычно это происходит, когда вы получаете доступ к конечной точке http и перенаправляете вас на конечную точку httpS. Тем не менее, библиотека должна сделать это за вас.   -  person fabrizioM    schedule 05.05.2015
comment
Также подозреваю, что, возможно, он хочет, чтобы конфигурация указывала конечную точку для вашего региона (у него есть поле для этого), а также думаю, что должен быть какой-то хороший способ, чтобы оно заполнялось автоматически -- есть EC2.DescribeRegions, но это кажется обратным.   -  person twotwotwo    schedule 06.05.2015
comment
@twotwotwo Указал s3-us-west-2.amazon.com в качестве конечной точки, но это не сработало.   -  person John    schedule 06.05.2015


Ответы (2)


Согласно Amazon:

Amazon S3 поддерживает доступ с виртуальным размещением и путем доступа во всех регионах. Однако синтаксис в стиле пути требует, чтобы вы использовали конечную точку для конкретного региона при попытке доступа к корзине. Например, если у вас есть ведро с именем mybucket, которое находится в ЕС, вы хотите использовать синтаксис в стиле пути, а объект называется puppy.jpg, правильный URI — http://s3-eu-west-1.amazonaws.com/mybucket/puppy.jpg. Вы получите ошибку PermanentRedirect, код ответа HTTP 301 и сообщение, указывающее правильный URI для вашего ресурса, если вы попытаетесь получить доступ к корзине за пределами стандартного региона США с синтаксисом пути, который использует любой из следующих:

  • http://s3.amazonaws.com

  • Конечная точка для региона, отличного от того, где находится сегмент, например, http://s3-eu-west-1.amazonaws.com для сегмента, созданного в регионе Запад США (Северная Калифорния).

Я думаю, проблема в том, что вы пытаетесь получить доступ к корзине не в том регионе. Ваш запрос будет здесь:

https://my-bucket-123.s3-us-west-2.amazonaws.com/test/123

Поэтому убедитесь, что my-bucket-123 действительно находится в us-west-2. (Я попробовал это со своим собственным ведром, и это сработало нормально)

Я также проверил, что он использует HTTPS, оборачивая вызовы: (их сообщение в журнале просто неверно)

type LogReadCloser struct {
    io.ReadCloser
}

func (lr *LogReadCloser) Read(p []byte) (int, error) {
    n, err := lr.ReadCloser.Read(p)
    log.Println(string(p))
    return n, err
}

type LogRoundTripper struct {
    http.RoundTripper
}

func (lrt *LogRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
    log.Println("REQUEST", req)
    res, err := lrt.RoundTripper.RoundTrip(req)
    log.Println("RESPONSE", res, err)
    res.Body = &LogReadCloser{res.Body}
    return res, err
}

А потом:

svc := s3.New(&aws.Config{
    Region:      "us-west-2",
    Credentials: cred,
    LogLevel:    0,
    HTTPClient:  &http.Client{Transport: &LogRoundTripper{http.DefaultTransport}},
})
person Caleb    schedule 06.05.2015
comment
Откуда ты знаешь, что это точно в нас-запад-2? В правом верхнем углу он просто упоминает глобальный. - person John; 07.05.2015
comment
В консоли AWS перейдите к S3, затем нажмите «Свойства» справа, а затем выберите свою корзину. Он покажет регион там. - person Caleb; 07.05.2015

Я думаю, вам лучше использовать S3 Uploader. Вот пример из моего кода, это веб-приложение, я использую gin framework, и в моем случае я получаю файл из веб-формы, загружаю его в s3 и получаю URL-адрес для представления страницы в других HTML:

// Create an S3 Uploader
  uploader := s3manager.NewUploader(sess)

  // Upload 
  result, err := uploader.Upload(&s3manager.UploadInput{
   Bucket: aws.String(bucket),
   Key: aws.String(fileHeader.Filename),
   Body: f,
  })
  if err != nil {
   c.HTML(http.StatusBadRequest, "create-project.html", gin.H{
    "ErrorTitle":   "S3 Upload Failed",
    "ErrorMessage": err.Error()})
  } else {
   // Success, print URL to Console.
   ///"result.Location is the URL of an Image"
   fmt.Println("Successfully uploaded to", result.Location)
  }

Полный пример с пошаговыми объяснениями можно найти здесь: https://www.matscloud.com/docs/cloud-sdk/go-and-s3/

person Mat Jovanovic    schedule 27.05.2020