赞
踩
开门见山的说,笔者已经被AWS坑的体无完肤了,文档难找、SDK版本繁多老版本没有注释、例子不全还有误导的情况、MD5-Hex不用一定要用MD5-Base64等等各种问题导致在使用的过程中各种卡壳,不过好在最终还是把问题解决,才有了今天给大家带来了【爬坑指南】,我们先从要做一件什么事情开始说起:
资源汇总:
首先上传文件并不难,from-data谁还不会呢?但是要把文件传好传安全很难,考虑点会非常多:
在根据业务的不同还有更多的扩展性要求。
如果当业务遇到文件上传场景的时候把这一套做了一遍,然后另外一个业务也需要使用在重来一遍就非常头疼了,所以就诞生出做一个通用的文件上传的想法了。
如果在遇到内部通讯协议使用Grpc或者是http-json为主,还需要对于网关鉴权进行改造和单独配置,会有非常多的额外成本,所以考虑使用前端直传的场景成本最低,而且因为各家云厂商提供的SDK成熟度高各项功能都有 (这里是第一个失策阿里云和腾讯云等都有非常完善的JS-SDK,没想到AWS提供的非常的简单)
并且前端也可以封装成一个标准SDK和后端对应,遇到文件上传场景抄起来就直接用就可以了。
整个流程大家可以参考下面这张流程图,整体分为五个阶段:
首先我们需要确定需要使用AWS的哪些能力:
package test import ( "context" "fmt" "testing" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" ) const AK = "XXXX" // AWS AK const SK = "XXXX" // AWS SK const BUCKET = "XXXX" // AWS BUCKET Name type Credential struct { Ak string Sk string } func (c *Credential) Retrieve(ctx context.Context) (aws.Credentials, error) { return aws.Credentials{ AccessKeyID: c.Ak, SecretAccessKey: c.Sk, }, nil } var client *s3.Client func init() { cred := &Credential{ Ak: AK, Sk: SK, } cfg := aws.Config{ Region: "ap-southeast-1", Credentials: cred, BearerAuthTokenProvider: nil, HTTPClient: nil, EndpointResolverWithOptions: nil, RetryMaxAttempts: 0, RetryMode: "", Retryer: nil, ConfigSources: nil, APIOptions: nil, Logger: nil, ClientLogMode: 0, DefaultsMode: "", RuntimeEnvironment: aws.RuntimeEnvironment{}, } client = s3.NewFromConfig(cfg) } func TestAWSV2PresignPutObject(t *testing.T) { fmt.Println("Create Presign client") presignClient := s3.NewPresignClient(client) filemd5 := "/SX1AAfPuVitH7ZK9bNg6Q==" // 前端上传文件给到 AWS-S3 时文件MD5校验(可选) fileLen := 5616111 // 前端上传文件给到 AWS-S3 时文件大小校验(可选) filename := "/demo/test.jpg" // 文件存储bucket的路径和名称 presignResult, err := presignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String(BUCKET), Key: aws.String(filename), ACL: types.ObjectCannedACLPrivate, ContentMD5: &filemd5, ContentLength: int64(fileLen), }, func(po *s3.PresignOptions) { // 授权时效 po.Expires = 48 * time.Hour }) if err != nil { panic("Couldn't get presigned URL for GetObject") } fmt.Printf("上传URL: %s\n", presignResult.URL) presignResult, err = presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(BUCKET), Key: aws.String(filename), }, func(po *s3.PresignOptions) { // 授权时效 po.Expires = 48 * time.Hour }) if err != nil { panic("Couldn't get presigned URL for GetObject") } fmt.Printf("访问URL: %s\n", presignResult.URL) }
使用上述代码我们就能得到以下内容:
上传URL: https://xxxx.s3.ap-southeast-1.amazonaws.com/demo/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASQSSOHDZ5AN5LXUF%2F20221021%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20221021T135608Z&X-Amz-Expires=172800&X-Amz-SignedHeaders=content-md5%3Bhost&x-id=PutObject&X-Amz-Signature=e23da84351a1afa7faaabfad533a26c8f2dbeb0b14fc4384560b40622726cbaa
访问URL: https://xxxx.s3.ap-southeast-1.amazonaws.com/demo/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASQSSOHDZ5AN5LXUF%2F20221021%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20221021T135608Z&X-Amz-Expires=172800&X-Amz-SignedHeaders=host&x-id=GetObject&X-Amz-Signature=7af80761fd063ed554827b5ab3e7d00b35cf67d98221157bbb39d247865a152e
我们可以通过postman来调用进行文件上传,使用put方式,binary上传文件二进制
这里千万不能使用from-data 因为上传访问是把所有的body内容保存在文件中,一定要使用binary的方式,如果你使用文件大小校验和md5校验一定会提示校验不通过,因为文件内容和实际文件内容不一样,如下:
----------------------------642585057435781546021821
Content-Disposition: form-data; name=""; filename="test.txt"
Content-Type: text/plain
omori
----------------------------642585057435781546021821--
对于使用了长度限制和MD5校验的前端在请求过程中需要在Headers里面增加对应的配置,才能通过sign校验,因为服务端在生成签名的时候 md5和len也参与了运算,http状态码返回200,恭喜你已经完成了上传动作了
AWS-S3使用的MD5-Base64,我们场景的MD5 32位是16进制的表示方式,但要注意不是讲16进制的MD5进行base64,是需要对原始的byte数组的MD5进行Base64,比如js-md5:
md5 = require('js-md5');
console.log(md5.base64("test"))
console.log(md5('test'))
console.log(md5.array('test'))
CY9rzUYh03PK3k6DJie09g== <-这个是正确的
098f6bcd4621d373cade4e832627b4f6
[
9, 143, 107, 205, 70,
33, 211, 115, 202, 222,
78, 131, 38, 39, 180,
246
]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。