介绍
业务场景中涉及到上传文件的场景,直接上传到服务端会受到带宽限制,大量用户并发上传会导致服务稳定性降低。
预签名URL中包含AK、有效期、资源、操作、签名等信息,任何使用该URL的人在有效期内都可以执行该URL对应的操作。这种方法称作预签名。
客户端首先从服务端获取需要上传的对象的预签名URL,然后客户端通过Http请求,将对象传至对象存储桶。
操作指引
获取对象存储 SDK访问密钥
在「对象存储-配置-密钥」生成对象存储SDK的访问密钥,标题栏为对象存储桶ID
预签名URL上传文件到对象存储
Golang代码示例
支持预签名的sdk详细使用说明文档如下
- •java-预签名
- •python-预签名
- •go-预签名
- •node.js-预签名
Go
复制package main
import (
"encoding/json"
"fmt"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos/enum"
"log"
"net/http"
)
func main() {
http.HandleFunc("/get_pre_sign_url", GetPreSignUrlHandler)
listenPort := ":8000"
if listenPort == "" {
log.Fatal("failed to load _FAAS_RUNTIME_PORT")
}
fmt.Println("http ListenAndServe ", listenPort)
log.Fatal(http.ListenAndServe(listenPort, nil))
}
var (
//填写从抖音云--对象存储--配置获取的AK和SK
accessKey = "xxxxxxxxxx"
secretKey = "xxxxxx"
// 如果部署在抖音云服务中,建议替换成内网域名
endpoint = "tos-cn-beijing.volces.com"
region = "cn-beijing"
// 填写从抖音云--对象存储获取的桶的ID
bucketName = "xxxxxxxxxx"
httpClient = &http.Client{}
)
func GetPreSignUrlHandler(w http.ResponseWriter, r *http.Request) {
// 初始化对象存储 client
client, err := tos.NewClientV2(endpoint, tos.WithRegion(region), tos.WithCredentials(tos.NewStaticCredentials(accessKey, secretKey)))
if err != nil {
fmt.Fprint(w, "client init error")
return
}
objectName := r.URL.Query().Get("object_name")
// 调用Tos SDK 生成上传对象预签名
url, err := client.PreSignedURL(&tos.PreSignedURLInput{
HTTPMethod: enum.HttpMethodPut,
Bucket: bucketName,
Key: objectName,
})
if err != nil {
fmt.Fprint(w, "get pre sign url error")
return
}
[removed]PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNS4wMDAwOCAyLjYwNDE3QzUuMDAwMDggMi40NTQ1OCA1LjEyMTMzIDIuMzMzMzMgNS4yNzA5MiAyLjMzMzMzSDEzLjM5NTlDMTMuNTQ1NSAyLjMzMzMzIDEzLjY2NjcgMi40NTQ1OCAxMy42NjY3IDIuNjA0MTdWMTAuNzI5MkMxMy42NjY3IDEwLjg3ODggMTMuNTQ1NSAxMSAxMy4zOTU5IDExSDEyLjMzMzNWNS4yNzA5MkMxMi4zMzMzIDQuMzg0OTYgMTEuNjE1MSAzLjY2Njc1IDEwLjcyOTIgMy42NjY3NUg1LjAwMDA4VjIuNjA0MTdaTTMuNjY2NzUgMy42NjY3NVYyLjYwNDE3QzMuNjY2NzUgMS43MTgyMiA0LjM4NDk0IDEgNS4yNzA5MiAxSDEzLjM5NTlDMTQuMjgxOSAxIDE1LjAwMDEgMS43MTgyMiAxNS4wMDAxIDIuNjA0MTdWMTAuNzI5MkMxNS4wMDAxIDExLjYxNTEgMTQuMjgxOSAxMi4zMzMzIDEzLjM5NTkgMTIuMzMzM0gxMi4zMzMzVjEzLjM5NTlDMTIuMzMzMyAxNC4yODE5IDExLjYxNTEgMTUuMDAwMSAxMC43MjkyIDE1LjAwMDFIMi42MDQxN0MxLjcxODIxIDE1LjAwMDEgMSAxNC4yODE5IDEgMTMuMzk1OVY1LjI3MDkyQzEgNC4zODQ5NiAxLjcxODIxIDMuNjY2NzUgMi42MDQxNyAzLjY2Njc1SDMuNjY2NzVaTTIuMzMzMzMgNS4yNzA5MkMyLjMzMzMzIDUuMTIxMzQgMi40NTQ1OSA1LjAwMDA4IDIuNjA0MTcgNS4wMDAwOEgxMC43MjkyQzEwLjg3ODcgNS4wMDAwOCAxMSA1LjEyMTM0IDExIDUuMjcwOTJWMTMuMzk1OUMxMSAxMy41NDU1IDEwLjg3ODcgMTMuNjY2NyAxMC43MjkyIDEzLjY2NjdIMi42MDQxN0MyLjQ1NDU5IDEzLjY2NjcgMi4zMzMzMyAxMy41NDU1IDIuMzMzMzMgMTMuMzk1OVY1LjI3MDkyWiIgZmlsbD0iIzE3MUExQyIgZmlsbC1vcGFjaXR5PSIwLjY1Ii8+Cjwvc3ZnPgo=" style="border-color: rgb(229, 231, 235); border-style: none; --tw-border-spacing-x:0; --tw-border-spacing-y:0; --tw-translate-x:0; --tw-translate-y:0; --tw-rotate:0; --tw-skew-x:0; --tw-skew-y:0; --tw-scale-x:1; --tw-scale-y:1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness:proximity; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width:0px; --tw-ring-offset-color:#fff; --tw-ring-color:rgba(59,130,246,0.5); --tw-ring-offset-shadow:0 0 #0000; --tw-ring-shadow:0 0 #0000; --tw-shadow:0 0 #0000; --tw-shadow-colored:0 0 #0000; --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; outline: none; display: block; height: auto; max-width: 100%; filter: unset !important;">复制html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="uploadFile" type="file">
<button onclick="upload()">上传</button>
<script>
function upload() {
const uploadFile = document.querySelector("#uploadFile");
const files = uploadFile.files;
let xhr = new XMLHttpRequest();
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(files[0]);
fileReader.onloadend = function() {
// 转换为二进制流
const binaryData = fileReader.result;
// 从服务端获取预签名URL, 本文档中获取预签名URL的接口名称为/get_pre_sign_url
xhr.open("PUT", "XXX");
xhr.onload = function(response) {
console.log('reponse', response);
}
xhr.send(binaryData);
};
}
</script>
</body>
</html>
UGC 内容审核后文件权限从私有读转为公开读
文件上传到对象存储后,默认为私有读。UGC 内容建议审核后再修改文件权限为公开读,否则存在内容违规风险。<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="705px" height="375px" viewBox="-0.5 -0.5 705 375">小程序 小程序服务端 5. 回源 CDN 4. 通过访问链接访问 对象存储 3. 服务端修改权限 文件 公开读 文件 私有读 1. 获取要上传文件的预签名url 2. 使用预签名的url 直接上传到对象存储 </svg>服务端Golang代码示例:修改文件权限为公开读Go
复制package main
import (
"context"
"fmt"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos"
"github.com/volcengine/ve-tos-golang-sdk/v2/tos/enum"
"log"
"net/http"
)
func main() {
http.HandleFunc("/put_object_public_read", PutObjectPublicReadHandler)
listenPort := ":8000"
if listenPort == "" {
log.Fatal("failed to load _FAAS_RUNTIME_PORT")
}
fmt.Println("http ListenAndServe ", listenPort)
log.Fatal(http.ListenAndServe(listenPort, nil))
}
var (
//填写从抖音云--对象存储--配置获取的AK和SK
accessKey = "xxxxxxxxxx"
secretKey = "xxxxxx"
// 如果部署在抖音云服务中,建议替换成内网域名
endpoint = "tos-cn-beijing.volces.com"
region = "cn-beijing"
// 填写从抖音云--对象存储获取的桶的ID
bucketName = "xxxxxxxxxx"
httpClient = &http.Client{}
)
func PutObjectPublicReadHandler(w http.ResponseWriter, r *http.Request) {
//初始化请求对象存储的client
client, err := tos.NewClientV2(endpoint, tos.WithRegion(region), tos.WithCredentials(tos.NewStaticCredentials(accessKey, secretKey)))
if err != nil {
fmt.Fprint(w, "client init error")
return
}
objectName := r.URL.Query().Get("object_name")
// 调用Tos SDK将对象访问权限变更公开读
acl := enum.ACLPublicRead
_, err = client.PutObjectACL(context.TODO(), &tos.PutObjectACLInput{Bucket: bucketName, Key: objectName, ACL: acl})
if err != nil {
fmt.Fprint(w, "PutObjectACL error")
return
}
w.Header().Set("content-type", "application/json")
w.Write([]byte("success"))
}
发表评论 取消回复