全部文档
当前文档

暂无内容

如果没有找到您期望的内容,请尝试其他搜索词

文档中心

通过外链上传文件(Go)

最近更新时间:2025-09-30 15:02:49

简单上传

1. 该方法上传的单文件大小不能超过5GB,超过5GB的文件请使用分块上传 。

2. 使用预签名链接时,请注意请求头必须与生成链接时的请求头一致,否则会有签名不一致的问题。

以下代码用于简单上传

package main

import (
    "fmt"
    "github.com/ks3sdklib/aws-sdk-go/aws"
    "github.com/ks3sdklib/aws-sdk-go/aws/credentials"
    "github.com/ks3sdklib/aws-sdk-go/service/s3"
    "net/http"
    "strings"
)

func main() {
    // 创建访问凭证,请将<AccessKeyID>与<SecretAccessKey>替换成真正的值
    cre := credentials.NewStaticCredentials("<AccessKeyID>", "<SecretAccessKey>", "")
    // 创建S3Client,更多配置项请查看Go-SDK初始化文档
    client := s3.New(&aws.Config{
        Credentials: cre,                          // 访问凭证
        Region:      "BEIJING",                    // 填写您的Region
        Endpoint:    "ks3-cn-beijing.ksyuncs.com", // 填写您的Endpoint
    })
    // 填写存储空间名称
    bucket := "<bucket_name>"
    // 填写对象的key
    key := "<object_key>"
    // 生成上传外链
    url, err := client.GeneratePresignedUrl(&s3.GeneratePresignedUrlInput{
        HTTPMethod:  s3.PUT,                    // 请求方法,可选值有 PUT, GET, DELETE, HEAD,必填
        Bucket:      aws.String(bucket),        // 存储空间名称,必填
        Key:         aws.String(key),           // 对象的key,必填
        Expires:     3600,                      // 过期时间,例如,3600(表示1小时),必填
        ACL:         aws.String("public-read"), // 对象访问权限,非必填
        ContentType: aws.String("text/plain"),  // 文件类型,非必填
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("结果:\n", url)

    // 通过外链上传,此处以Golang代码为例,也可以通过其他方式上传
    httpReq, err := http.NewRequest("PUT", url, strings.NewReader("这是一段测试文本"))
    if err != nil {
        panic(err)
    }
    // 实际上传时的请求头必须与生成链接时的请求头一致,否则会有签名不一致的问题
    httpReq.Header.Add("x-amz-acl", "public-read")
    httpReq.Header.Add("Content-Type", "text/plain")
    resp, err := http.DefaultClient.Do(httpReq)
    if err != nil {
        panic(err)
    }
    fmt.Println("上传结果:\n", *resp)
}

分块上传

1. 单文件大小超过5GB时必须采用分块上传。

2. 使用预签名链接时,请注意请求头必须与生成链接时的请求头一致,否则会有签名不一致的问题。

以下代码用于分块上传:

package main

import (
    "fmt"
    "github.com/ks3sdklib/aws-sdk-go/aws"
    "github.com/ks3sdklib/aws-sdk-go/aws/awsutil"
    "github.com/ks3sdklib/aws-sdk-go/aws/credentials"
    "github.com/ks3sdklib/aws-sdk-go/service/s3"
    "io"
    "net/http"
    "os"
    "strconv"
)

func main() {
    // 创建访问凭证,请将<AccessKeyID>与<SecretAccessKey>替换成真正的值
    cre := credentials.NewStaticCredentials("<AccessKeyID>", "<SecretAccessKey>", "")
    // 创建S3Client,更多配置项请查看Go-SDK初始化文档
    client := s3.New(&aws.Config{
        Credentials: cre,                          // 访问凭证
        Region:      "BEIJING",                    // 填写您的Region
        Endpoint:    "ks3-cn-beijing.ksyuncs.com", // 填写您的Endpoint
    })
    // 填写存储空间名称
    bucket := "<bucket_name>"
    // 填写对象的Key
    key := "<object_key>"
    // 1. 初始化分块上传
    initRes, err := client.CreateMultipartUpload(&s3.CreateMultipartUploadInput{
        Bucket: aws.String(bucket), // 存储空间名称,必填
        Key:    aws.String(key),    // 对象的key,必填
    })
    if err != nil {
        panic(err)
    }
    // 获取分块上传Id
    uploadId := *initRes.UploadID
    fmt.Println("init success, uploadId:", uploadId)
    // 打开文件
    file, err := os.Open("/Users/test/demo.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    stat, err := file.Stat()
    if err != nil {
        panic(err)
    }
    var fileSize = stat.Size()                   // 文件大小
    var partSize int64 = 5 * 1024 * 1024         // 分块大小为5MB
    var compParts []*s3.CompletedPart            // 已上传分块序号和etag信息,用于合并分块
    var totalPartNum = (fileSize-1)/partSize + 1 // 计算总分块数

    // 2. 分块上传
    for partNum := int64(1); partNum <= totalPartNum; partNum++ {
        offset := (partNum - 1) * partSize // 分块偏移量
        actualPartSize := partSize
        if offset+partSize >= fileSize {
            actualPartSize = fileSize - offset
        }

        // 生成上传单个分块外链
        url, err := client.GeneratePresignedUrl(&s3.GeneratePresignedUrlInput{
            HTTPMethod: s3.PUT,             // 请求方法,可选值有 PUT, GET, DELETE, HEAD, POST,必填
            Bucket:     aws.String(bucket), // 存储空间名称,必填
            Key:        aws.String(key),    // 对象的key,必填
            Expires:    3600,               // 过期时间,例如,3600(表示1小时),必填
            ExtendQueryParams: map[string]*string{
                "partNumber": aws.String(strconv.FormatInt(partNum, 10)), // 分块序号,必填
                "uploadId":   aws.String(uploadId),                       // 分块上传ID,必填
            },
        })
        if err != nil {
            panic(err)
        }
        fmt.Printf("已生成第%d块上传外链, url:%s\n", partNum, url)
        // 通过外链上传块,此处以Golang代码为例,也可以通过其他方式上传
        request, err := http.NewRequest("PUT", url, io.NewSectionReader(file, offset, actualPartSize))
        if err != nil {
            panic(err)
        }
        // 发送请求
        resp, err := http.DefaultClient.Do(request)
        if err != nil {
            panic(err)
        }
        if resp.StatusCode != 200 {
            panic("上传失败")
        }
        // 已上传分块序号和etag信息,用于合并分块
        etag := resp.Header.Get("ETag")
        compParts = append(compParts, &s3.CompletedPart{PartNumber: aws.Long(partNum), ETag: aws.String(etag)})
        fmt.Printf("已上传第%d块, etag:%s\n", partNum, etag)
    }

    // 3. 完成分块上传(合并分块)
    compRes, _ := client.CompleteMultipartUpload(&s3.CompleteMultipartUploadInput{
        Bucket:   aws.String(bucket),   // 存储空间名称,必填
        Key:      aws.String(key),      // 对象的key,必填
        UploadID: aws.String(uploadId), // 分块上传ID,必填
        MultipartUpload: &s3.CompletedMultipartUpload{
            Parts: compParts, // 已上传分块序号和etag信息,用于合并分块,必填
        },
    })
    fmt.Println("结果:\n", awsutil.StringValue(compRes))
}

文档导读
纯净模式常规模式

纯净模式

点击可全屏预览文档内容
文档反馈