This skill should be used when the user asks to "implement cloud storage", "upload file to S3", "generate presigned URL", "阿里云 OSS", "AWS S3", "文件上传", "云存储", or needs to implement file storage including AWS S3, Aliyun OSS, presigned URLs, file upload and download, and cloud storage integration.
type AliOss struct {
Endpoint string `json:",default=https://oss-accelerate.aliyuncs.com"`
AccessKey string
AccessSecret string
BucketName string
Region string
}
type AwsOss struct {
Endpoint string `json:",optional"`
AccessKey string
AccessSecret string
BucketName string
Region string
Domain string // CDN 加速域名
}
import (
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type ossClient struct {
AliClient *s3.Client
AliPreSignClient *s3.PresignClient
AliBucketName string
AwsClient *s3.Client
AwsPreSignClient *s3.PresignClient
AwsBucketName string
}
func InitOss(aliOss AliOss, awsOss AwsOss) {
// 阿里云 OSS
if len(aliOss.AccessKey) > 0 {
aliOps := s3.Options{
Credentials: credentials.NewStaticCredentialsProvider(aliOss.AccessKey, aliOss.AccessSecret, ""),
BaseEndpoint: &aliOss.Endpoint,
Region: aliOss.Region,
}
aliClient := s3.New(aliOps)
ossClients.AliClient = aliClient
ossClients.AliPreSignClient = s3.NewPresignClient(aliClient)
ossClients.AliBucketName = aliOss.BucketName
}
// AWS S3
awsOps := s3.Options{
Credentials: credentials.NewStaticCredentialsProvider(awsOss.AccessKey, awsOss.AccessSecret, ""),
Region: awsOss.Region,
}
awsClient := s3.New(awsOps)
ossClients.AwsPreSignClient = s3.NewPresignClient(awsClient)
ossClients.AwsBucketName = awsOss.BucketName
}
func PresignUploadUrl(objName, ossType, contentType string) (string, error) {
if ossType == "ali" {
req := &s3.PutObjectInput{
Bucket: &ossClients.AliBucketName,
Key: &objName,
ContentType: &contentType,
}
presignedReq, _ := ossClients.AliPreSignClient.PresignPutObject(context.TODO(), req,
s3.WithPresignExpires(15*time.Minute))
return presignedReq.URL, nil
}
// AWS S3
req := &s3.PutObjectInput{
Bucket: &ossClients.AwsBucketName,
Key: &objName,
}
presignedReq, _ := ossClients.AwsPreSignClient.PresignPutObject(context.TODO(), req)
// 替换为 CDN 域名
presignedReq.URL = replaceDomain(presignedReq.URL, "cdn.example.com")
return presignedReq.URL, nil
}
func replaceDomain(url, newDomain string) string {
index := strings.Index(url[8:], "/")
return "https://" + newDomain + url[index+8:]
}
func UploadFile(ctx context.Context, objName string, contentType string, body *bytes.Buffer) (string, error) {
req := &s3.PutObjectInput{
Bucket: &ossClients.AliBucketName,
Key: &objName,
ContentType: ptr.String(contentType),
Body: body,
}
_, err := ossClients.AliClient.PutObject(ctx, req)
if err != nil {
return "", err
}
return fmt.Sprintf("https://%s.oss-accelerate.aliyuncs.com/%s", ossClients.AliBucketName, objName), nil
}
func GetDownloadUrl(objName string) string {
return fmt.Sprintf("https://%s.oss-accelerate.aliyuncs.com/%s", ossClients.AliBucketName, objName)
}
// 前端请求预签名 URL
url, _ := PresignUploadUrl("avatar/user123.png", "ali", "image/png")
// 前端使用 PUT 上传
// curl -X PUT -H "Content-Type: image/png" -d "@file.png" "https://..."
// 服务端直接上传
file, _ := os.Open("localfile.png")
defer file.Close()
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
io.Copy(buffer, file)
uploadUrl, _ := UploadFile(ctx, "avatar/user123.png", "image/png", buffer)