Reputation: 3115
I'm having a bit of trouble saving a file in golang with the AWS S3 go sdk (https://github.com/awslabs/aws-sdk-go).
This is what I have:
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))
}
I keep receiving a 301 Moved Permanently
response.
Edit: I created the bucket manually. Edit #2: Example response:
---[ 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 sign is http as well.
Upvotes: 2
Views: 7548
Reputation: 21
I think you're better off using the S3 Uploader. Here's an example from my code, it's a web app, I use gin framework, and in my case I get a file from a web form, upload it to s3, and retrieve the URL to present a page in other HTMLs:
// 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)
}
You can find an entire example here, explained step by step: https://www.matscloud.com/docs/cloud-sdk/go-and-s3/
Upvotes: 2
Reputation: 9458
According to Amazon:
Amazon S3 supports virtual-hosted-style and path-style access in all regions. The path-style syntax, however, requires that you use the region-specific endpoint when attempting to access a bucket. For example, if you have a bucket called mybucket that resides in the EU, you want to use path-style syntax, and the object is named puppy.jpg, the correct URI is http://s3-eu-west-1.amazonaws.com/mybucket/puppy.jpg. You will receive a "PermanentRedirect" error, an HTTP response code 301, and a message indicating what the correct URI is for your resource if you try to access a bucket outside the US Standard region with path-style syntax that uses either of the following:
An endpoint for a region different from the one where the bucket resides, for example, http://s3-eu-west-1.amazonaws.com for a bucket that was created in the US West (Northern California) region
I think the problem is that you are trying to access a bucket in the wrong region. Your request is going here:
https://my-bucket-123.s3-us-west-2.amazonaws.com/test/123
So make sure that my-bucket-123
is actually in us-west-2
. (I tried this with my own bucket and it worked fine)
I also verified that it's using HTTPS by wrapping the calls: (their log message is just wrong)
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
}
And then:
svc := s3.New(&aws.Config{
Region: "us-west-2",
Credentials: cred,
LogLevel: 0,
HTTPClient: &http.Client{Transport: &LogRoundTripper{http.DefaultTransport}},
})
Upvotes: 3