1. 程式人生 > >Go實戰--golang上傳檔案到七牛雲物件儲存(github.com/qiniu/api.v7)

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 }

斷點續傳

斷點續傳,官方給出了完整了例子,這裡就不貼程式碼了。

這裡寫圖片描述