Go實戰--golang上傳檔案到七牛雲物件儲存(github.com/qiniu/api.v7)
生命不止,繼續 go go go !!!
在國內,七牛絕對是golang的領導者。
七牛雲
關於七牛:
(七牛雲)隸屬於上海七牛資訊科技有限公司,七牛雲是國內領先的企業級雲服務商,專注於以資料管理為中心的雲端計算業務研發和運營,圍繞富媒體場景推出了物件儲存、融合 CDN 加速、容器計算雲、大資料平臺、人工智慧平臺等產品,並提供一站式視訊雲解決方案。公司目前已位列國內雲端計算行業第一陣營,為 70 多萬家企業提供服務。
接下來開始七牛之旅:
註冊
驗證
支付寶驗證
新增資源(物件儲存):
輸入儲存空間名稱,也就是bucket
選擇儲存區域,有華東、華北、華南、北美
選擇訪問控制,有公開空間和私有空間選擇
Go SDK
關於物件儲存,七牛雲提供了Golang版本的SDK。
簡介
此 SDK 適用於 Go 1.7.0 及以上版本。使用此 SDK 構建您的網路應用程式,能讓您以非常便捷的方式將資料安全地儲存到七牛雲上。無論您的網路應用是一個網站程式,還是包括從雲端(服務端程式)到終端(手持裝置應用)的架構服務和應用,通過七牛雲及其 SDK,都能讓您應用程式的終端使用者高速上傳和下載,同時也讓您的服務端更加輕盈。
Go SDK 屬於七牛服務端SDK之一,主要有如下功能:
提供生成客戶端上傳所需的上傳憑證的功能
提供檔案從服務端直接上傳七牛的功能
提供對七牛空間中檔案進行管理的功能
提供對七牛空間中檔案進行處理的功能
提供七牛CDN相關的重新整理,預取,日誌功能
獲取
go get -u github.com/qiniu/api.v7
獲取的時候出現錯誤:
# cd D:\go_workspace\src\golang.org\x\net; git pull --ff-only
fatal: unable to access 'https://go.googlesource.com/net/': Failed to connect to go.googlesource.com port 443: Timed out
package golang.org/x/net/context: exit status 1
原因呢,你懂的,自己想辦法解決~~~
上傳檔案
七牛檔案上傳分為客戶端上傳(主要是指網頁端和移動端等面向終端使用者的場景)和服務端上傳兩種場景,具體可以參考文件七牛業務流程。
這裡跟大家分享的,主要是客戶端上傳。
服務端SDK在上傳方面主要提供兩種功能,一種是生成客戶端上傳所需要的上傳憑證,另外一種是直接上傳檔案到雲端。
相關知識介紹
Access Key 和 Secret Key
在七牛雲的控制面板中, 個人中心,金鑰管理中可以檢視自己的*Access Key 和 Secret Key。
客戶端上傳憑證
客戶端(移動端或者Web端)上傳檔案的時候,需要從客戶自己的業務伺服器獲取上傳憑證,而這些上傳憑證是通過服務端的SDK來生成的,然後通過客戶自己的業務API分發給客戶端使用。根據上傳的業務需求不同,七牛雲 Go SDK支援豐富的上傳憑證生成方式。
這裡的bucket即你在七牛雲設定的儲存空間名稱,accessKey, secretKey即上面提到的。
putPolicy := storage.PutPolicy{
Scope: bucket,
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
表示檔案上傳的上傳策略
type PutPolicy struct {
Scope string `json:"scope"`
Expires uint32 `json:"deadline"` // 截止時間(以秒為單位)
IsPrefixalScope int `json:"isPrefixalScope,omitempty"`
InsertOnly uint16 `json:"insertOnly,omitempty"` // 若非0, 即使Scope為 Bucket:Key 的形式也是insert only
DetectMime uint8 `json:"detectMime,omitempty"` // 若非0, 則服務端根據內容自動確定 MimeType
FsizeLimit int64 `json:"fsizeLimit,omitempty"`
MimeLimit string `json:"mimeLimit,omitempty"`
SaveKey string `json:"saveKey,omitempty"`
CallbackFetchKey uint8 `json:"callbackFetchKey,omitempty"`
CallbackURL string `json:"callbackUrl,omitempty"`
CallbackHost string `json:"callbackHost,omitempty"`
CallbackBody string `json:"callbackBody,omitempty"`
CallbackBodyType string `json:"callbackBodyType,omitempty"`
ReturnURL string `json:"returnUrl,omitempty"`
ReturnBody string `json:"returnBody,omitempty"`
PersistentOps string `json:"persistentOps,omitempty"`
PersistentNotifyURL string `json:"persistentNotifyUrl,omitempty"`
PersistentPipeline string `json:"persistentPipeline,omitempty"`
EndUser string `json:"endUser,omitempty"`
DeleteAfterDays int `json:"deleteAfterDays,omitempty"`
FileType int `json:"fileType,omitempty"`
}
指定憑證有效時間
預設情況下,在不指定上傳憑證的有效時間情況下,預設有效期為1個小時。也可以自行指定上傳憑證的有效期:
putPolicy.Expires = 3600 //1小時有效期
這裡的時間單位是秒。
構建配置類
七牛儲存支援空間建立在不同的機房,在使用七牛的 Go SDK 中的FormUploader和ResumeUploader上傳檔案之前,必須要構建一個上傳用的Config物件,在該物件中,可以指定空間對應的zone以及其他的一些影響上傳的引數。
Config 為檔案上傳,資源管理等配置
type Config struct {
Zone *Zone //空間所在的機房
UseHTTPS bool //是否使用https域名
UseCdnDomains bool //是否使用cdn加速域名
}
我們可以這麼寫:
cfg := storage.Config{}
// 空間對應的機房
cfg.Zone = &storage.ZoneHuadong
// 是否使用https域名
cfg.UseHTTPS = false
// 上傳是否使用CDN上傳加速
cfg.UseCdnDomains = false
這裡需要注意的是cfg.Zone,還記得之前新增資源的時候,選擇的區域嗎?
華東 storage.ZoneHuadong
華北 storage.ZoneHuabei
華南 storage.ZoneHuanan
北美 storage.ZoneBeimei
表單上傳的額外可選項
// PutExtra 為表單上傳的額外可選項
type PutExtra struct {
// 可選,使用者自定義引數,必須以 "x:" 開頭。若不以x:開頭,則忽略。
Params map[string]string
// 可選,當為 "" 時候,服務端自動判斷。
MimeType string
// 上傳事件:進度通知。這個事件的回撥函式應該儘可能快地結束。
OnProgress func(fsize, uploaded int64)
}
標準的上傳回復內容
如果使用了上傳回調或者自定義了returnBody,那麼需要根據實際情況,自己自定義一個返回值結構體
type PutRet struct {
Hash string `json:"hash"`
PersistentID string `json:"persistentId"`
Key string `json:"key"`
}
表單上傳的物件
FormUploader 表示一個表單上傳的物件
type FormUploader struct {
client *rpc.Client
cfg *Config
}
構建一個表單上傳的物件
func NewFormUploader(cfg *Config) *FormUploader {
if cfg == nil {
cfg = &Config{}
}
return &FormUploader{
client: &rpc.DefaultClient,
cfg: cfg,
}
}
以表單方式上傳一個檔案
PutFile 用來以表單方式上傳一個檔案,和 Put 不同的只是一個通過提供檔案路徑來訪問檔案內容,一個通過 io.Reader 來訪問。
func (p *FormUploader) PutFile(
ctx context.Context, ret interface{}, uptoken, key, localFile string, extra *PutExtra) (err error) {
return p.putFile(ctx, ret, uptoken, key, true, localFile, extra)
}
各個引數:
ctx 是請求的上下文。
ret 是上傳成功後返回的資料。如果 uptoken 中沒有設定 callbackUrl 或 returnBody,那麼返回的資料結構是 PutRet 結構。
uptoken 是由業務伺服器頒發的上傳憑證。
key 是要上傳的檔案訪問路徑。比如:”foo/bar.jpg”。注意我們建議 key 不要以 ‘/’ 開頭。另外,key 為空字串是合法的。
localFile 是要上傳的檔案的本地路徑。
extra 是上傳的一些可選項,可以指定為nil。詳細見 PutExtra 結構的描述。
實戰
檔案上傳(表單方式)
直接上程式碼了,要把accessKey和secretKey換成你自己的!!!!
package main
import (
"context"
"fmt"
"github.com/qiniu/api.v7/auth/qbox"
"github.com/qiniu/api.v7/storage"
)
func main() {
accessKey := "TgVGKnpCMLDI6hSS4rSWE3g-FZjMPf6Zbc******"
secretKey := "zqZvH3fNVaggw00oc9wCrcWKgeeiV7WITF******"
localFile := "1.png"
bucket := "wangshubotest"
key := "1.png"
putPolicy := storage.PutPolicy{
Scope: bucket,
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
cfg := storage.Config{}
cfg.Zone = &storage.ZoneHuadong
cfg.UseHTTPS = false
cfg.UseCdnDomains = false
formUploader := storage.NewFormUploader(&cfg)
ret := storage.PutRet{}
putExtra := storage.PutExtra{
Params: map[string]string{
"x:name": "github logo",
},
}
err := formUploader.PutFile(context.Background(), &ret, upToken, key, localFile, &putExtra)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret.Key, ret.Hash)
}
輸出:
1.png FhR37vPVvgaAKJl56iaR5nLip-jM
登入七牛雲,在內容管理中可以看到我們上傳的檔案
覆蓋七牛雲上已經存在的檔案
我們想替換七牛雲上1.png檔案,我們重新選一個本地檔案命名為1.png,然後執行上面的程式碼,結果輸出:
file exists
那我們應該如何覆蓋?
其實,很簡單,我們要知道想要覆蓋的檔名稱,這裡就是1.png
package main
import (
"context"
"fmt"
"github.com/qiniu/api.v7/auth/qbox"
"github.com/qiniu/api.v7/storage"
)
func main() {
accessKey := "TgVGKnpCMLDI6hSS4rSWE3g-FZjMPf6Zbc******"
secretKey := "zqZvH3fNVaggw00oc9wCrcWKgeeiV7WITF******"
localFile := "1.png"
bucket := "wangshubotest"
key := "1.png"
keyToOverwrite := "1.png"
putPolicy := storage.PutPolicy{
Scope: fmt.Sprintf("%s:%s", bucket, keyToOverwrite),
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
cfg := storage.Config{}
// 空間對應的機房
cfg.Zone = &storage.ZoneHuadong
// 是否使用https域名
cfg.UseHTTPS = false
// 上傳是否使用CDN上傳加速
cfg.UseCdnDomains = false
// 構建表單上傳的物件
formUploader := storage.NewFormUploader(&cfg)
ret := storage.PutRet{}
// 可選配置
putExtra := storage.PutExtra{
Params: map[string]string{
"x:name": "github logo",
},
}
err := formUploader.PutFile(context.Background(), &ret, upToken, key, localFile, &putExtra)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret.Key, ret.Hash)
}
我們可以看到,檔案已經被覆蓋。
上傳檔案自定義返回值結構體
之前的兩段程式碼,上傳檔案的返回都是key和hash,我們是可以自己定義的,主要是設定ReturnBody:
package main
import (
"context"
"fmt"
"github.com/qiniu/api.v7/auth/qbox"
"github.com/qiniu/api.v7/storage"
)
// 自定義返回值結構體
type MyPutRet struct {
Key string
Hash string
Fsize int
Bucket string
Name string
}
func main() {
accessKey := "TgVGKnpCMLDI6hSS4rSWE3g-FZjMPf6Zbc******"
secretKey := "zqZvH3fNVaggw00oc9wCrcWKgeeiV7WITF******"
localFile := "1.png"
bucket := "wangshubotest"
key := "1.png"
putPolicy := storage.PutPolicy{
Scope: bucket,
ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}`,
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
cfg := storage.Config{}
// 空間對應的機房
cfg.Zone = &storage.ZoneHuadong
// 是否使用https域名
cfg.UseHTTPS = false
// 上傳是否使用CDN上傳加速
cfg.UseCdnDomains = false
// 構建表單上傳的物件
formUploader := storage.NewFormUploader(&cfg)
ret := MyPutRet{}
// 可選配置
putExtra := storage.PutExtra{
Params: map[string]string{
"x:name": "github logo",
},
}
err := formUploader.PutFile(context.Background(), &ret, upToken, key, localFile, &putExtra)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret)
}
輸出:
{1.png Fn616MXMfraD1V_u_TKIjC3X491Z 28540 wangshubotest github logo}
位元組陣列上傳(表單方式)
這裡用到的Put而不是PutFile。
Put 用來以表單方式上傳一個檔案。
func (p *FormUploader) Put(
ctx context.Context, ret interface{}, uptoken, key string, data io.Reader, size int64, extra *PutExtra) (err error) {
err = p.put(ctx, ret, uptoken, key, true, data, size, extra, path.Base(key))
return
}
各個引數含義:
ctx 是請求的上下文。
ret 是上傳成功後返回的資料。如果 uptoken 中沒有設定 callbackUrl 或 returnBody,那麼返回的資料結構是 PutRet 結構。
uptoken 是由業務伺服器頒發的上傳憑證。
key 是要上傳的檔案訪問路徑。比如:”foo/bar.jpg”。注意我們建議 key 不要以 ‘/’ 開頭。另外,key 為空字串是合法的。
data 是檔案內容的訪問介面(io.Reader)。
fsize 是要上傳的檔案大小。
extra 是上傳的一些可選項。可以指定為nil。詳細見 PutExtra 結構的描述。
package main
import (
"bytes"
"context"
"fmt"
"github.com/qiniu/api.v7/auth/qbox"
"github.com/qiniu/api.v7/storage"
)
// 自定義返回值結構體
type MyPutRet struct {
Key string
Hash string
Fsize int
Bucket string
Name string
}
func main() {
accessKey := "TgVGKnpCMLDI6hSS4rSWE3g-FZjMPf6Zbc******"
secretKey := "zqZvH3fNVaggw00oc9wCrcWKgeeiV7WITF******"
bucket := "wangshubotest"
key := "2.log"
putPolicy := storage.PutPolicy{
Scope: bucket,
}
mac := qbox.NewMac(accessKey, secretKey)
upToken := putPolicy.UploadToken(mac)
cfg := storage.Config{}
cfg.Zone = &storage.ZoneHuadong
cfg.UseHTTPS = false
cfg.UseCdnDomains = false
formUploader := storage.NewFormUploader(&cfg)
ret := MyPutRet{}
// 可選配置
putExtra := storage.PutExtra{
Params: map[string]string{
"x:name": "github logo",
},
}
data := []byte("welcome to the hotel")
dataLen := int64(len(data))
err := formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(data), dataLen, &putExtra)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ret)
}
輸出:
{2.log Fh3tNUEoiaj-qkNcP915nRuiAm4- 0 }
斷點續傳
斷點續傳,官方給出了完整了例子,這裡就不貼程式碼了。