这是我参与「第五届青训营」笔记创作活动的第10天。
今天主要是分享使用阿里云OSS对象存储技术实现视频流和头像的上传。
阿里OSS工作原理
OSS工作原理
数据以对象(Object)的形式存储在OSS的存储空间(Bucket )中。如果要使用OSS存储数据,需要先创建Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后,您可以将数据以Object的形式上传到Bucket,并指定Object的文件名(Key)作为其唯一标识。
OSS以HTTP RESTful API的形式对外提供服务,访问不同地域需要不同的访问域名(Endpoint)。当您请求访问OSS时,OSS通过使用访问密钥(AccessKey ID和AccessKey Secret)对称加密的方法来验证某个请求的发送者身份。
Object操作在OSS上具有原子性和强一致性。
-
存储空间
存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。
-
对象
对象是OSS存储数据的基本单元,也被称为OSS的文件。和传统的文件系统不同,对象没有文件目录层级结构的关系。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成,并且由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。
-
对象名称
在各语言SDK中,ObjectKey、Key以及ObjectName是同一概念,均表示对Object执行相关操作时需要填写的Object名称。例如向某一存储空间上传Object时,ObjectKey表示上传的Object所在存储空间的完整名称,即包含文件后缀在内的完整路径,如填写为abc/efg/123.jpg。
-
地域
Region表示OSS的数据中心所在物理位置。用户可以根据费用、请求来源等选择合适的地域创建Bucket。一般来说,距离用户更近的Region访问速度更快。详情请参见OSS已经开通的Region。
-
访问域名
Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同的Region的时候,需要不同的域名。通过内网和外网访问同一个Region所需要的Endpoint也是不同的。例如杭州Region的外网Endpoint是oss-cn-hangzhou.aliyuncs.com,内网Endpoint是oss-cn-hangzhou-internal.aliyuncs.com。具体的内容请参见各个Region对应的Endpoint。
-
访问密钥
AccessKey简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。OSS通过使用AccessKeyId和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户;AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,必须保密。对于OSS来说,AccessKey的来源有:
- Bucket的拥有者申请的AccessKey。
- 被Bucket的拥有者通过RAM授权给第三方请求者的AccessKey。
- 被Bucket的拥有者通过STS授权给第三方请求者的AccessKey。
更多AccessKey介绍请参见创建AccessKey。
-
强一致性
Object操作在OSS上具有原子性,操作要么成功要么失败,不会存在有中间状态的Object。OSS保证用户一旦上传完成之后读到的Object是完整的,OSS不会返回给用户一个部分上传成功的Object。
Object操作在OSS同样具有强一致性,用户一旦收到了一个上传(PUT)成功的响应,该上传的Object就已经立即可读,并且Object的冗余数据已经写成功。不存在一种上传的中间状态,即read-after-write却无法读取到数据。对于删除操作也是一样的,用户删除指定的Object成功之后,该Object立即变为不存在。
视频流和视频封面上传至阿里OSS对象存储
在阿里云OSS控制台创建一个公共读的bucket
如下图所示:
进行阿里云OSS代码的编写
阿里云OSS初始化相关代码的编写:
- 通过EndPoint,AccessKeyID,AccessKeySecret连接到个人的阿里云OSS账户,得到client。
- 利用该client连接到之前创建好的bucket。
- 将这个bucket赋值给全局变量g.OssBucket,便于后续上传下载时的调用。
func OSSInit() {
once.Do(func() {
// 连接OSS账户
client, err := oss.New(ossRelated.EndPoint, ossRelated.AccessKeyID, ossRelated.AccessKeySecret)
if err != nil {
g.Logger.Infof("连接OSS账户失败" + err.Error())
} else { // OSS账户连接成功
// 连接存储空间
bucket, err = client.Bucket(ossRelated.BucketName)
if err != nil {
g.Logger.Infof("连接存储空间失败" + err.Error())
} else { // 存储空间连接成功
g.Logger.Infof("OSS初始化完成")
}
}
})
g.OssBucket = bucket
}
阿里云OSS上传视频、图片文件相关代码的编写:
指定需要上传的字节流文件和上传后的文件路径即可
在视频流模块,我们还需要通过ffmpeg截取视频的封面,然后将视频封面上传至阿里云OSS的bucket中。故fileType有video、picture两种。
func UploadFile(file []byte, filename string, fileType string) bool {
var fileSuffix string
if fileType == "video" {
fileSuffix = ".mp4"
} else if fileType == "picture" {
fileSuffix = ".jpg"
} else {
g.Logger.Infof("无法上传" + fileType + "类型文件")
return false
}
//指定需要上传的字节流文件和上传后的文件路径
err := g.OssBucket.PutObject("video/"+filename+fileSuffix, bytes.NewReader(file))
if err != nil {
g.Logger.Infof("上传文件失败" + err.Error())
return false
} else {
return true
}
}
使用ffmpeg截取视频封面并上传至云端
首先需要下载ffmpeg至项目路径下:
cmd := exec.Command(ossRelated.FfmpegPath, "-i", videoURL, "-y", "-f", "image2", "-ss", "1", picturePath)
cmd.Run()
这两句代码可以将videoURL对应的云端video拉取下来,并截取该video的第一帧至本地的picturePath路径下。
然后以字节数组的形式读出本地的封面图,再调用前面编写好的UploadFile函数即可将封面图上传到云端。
openFile, err := os.Open(picturePath)
pictureBytes, err := ioutil.ReadAll(openFile)
视频头像上传至阿里OSS对象存储
在目前的抖声项目中,需要加入头像初始化的功能。
在此,我准备了10张系统预设头像,提前放入了项目路径下。
具体实现思路如下:
- 用户注册成功后会得到一个UserID,由UserID对10取模后的值决定选取哪张图片作为用户初始头像。
- 被选定的头像会被上传至阿里云OSS的bucket的avatar目录下,并以"userID_avatar.jpg"的格式来命名,每个用户在云端拥有一个唯一的头像文件名。
在其他服务接口需要获取auther或user的avatarURL时,只需要调用GetAvatar(userID int)函数对该UserID的avatarURL进行返回即可。
//user Service层
// GetAvatar 获取用户头像
func GetAvatar(userID int) string {
strUserID := strconv.Itoa(userID)
avatarURL := ossRelated.OSSAvatarPreURL + strUserID + "_avatar.jpg"
return avatarURL
}
总结
今天分享了使用阿里OSS对象存储实现大项目的视频、封面、头像的上传功能的具体流程。