Go --- 七牛雲 上傳文件 & Token demo

package main
 
import (
    "bytes"
    "crypto/hmac"
    "crypto/sha1"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "io/ioutil"
    "mime/multipart"
    "net/http"
    "os"
    "path/filepath"
    "time"
)
 
var (
    AccessKey = "MYqxCWi4Nrv114F4LeLaD9ekYTgnNdgvrBkyVvRS"
    SecretKey = "rHRBY7WTffwK5Na064oVm33sLKyg-Efph3KllhEa"
)
 
func main() {
    /*官網文檔  https://developer.qiniu.com/kodo/manual/1208/upload-token
    用戶根據業務需求,肯定上傳策略要素,構造出具體的上傳策略。例如用戶要向空間 my-bucket 上傳一個名爲 sunflower.jpg 的圖片,受權有效期截止到 2015-12-31 00:00:00(該有效期指上傳完成後在七牛生成文件的時間,而非上傳的開始時間),而且但願獲得圖片的名稱、大小、寬高和校驗值。那麼相應的上傳策略各字段分別爲:
    scope = 'my-bucket:sunflower.jpg'
    deadline = 1451491200
    returnBody = '{
                "name": $(fname),
                "size": $(fsize),
                "w": $(imageInfo.width),
                "h": $(imageInfo.height),
                "hash": $(etag)
    }'
    */
    putPolicy := map[string]interface{}{}
    putPolicy["scope"] = "public:qiniuyun.go"
    putPolicy["deadline"] = time.Now().Unix() + int64(time.Hour/time.Second) //截至時間!!!一開始寫了有效時長上去,並且1s是1e9 。。。
    putPolicy["insertOnly"] = 0
    putPolicy["returnBody"] = `{
            "name": "$(fname)",
            "size": "$(fsize)",
            "w": "$(imageInfo.width)",
            "h": "$(imageInfo.height)",
            "hash": "$(etag)"
        }`
    putPolicyBytes, err := json.Marshal(putPolicy)
    if err != nil {
        panic(err.Error())
    }
    fmt.Println("putPolicy:", string(putPolicyBytes))
    encodedPutPolicy := base64.URLEncoding.EncodeToString(putPolicyBytes)
    fmt.Println("encodePutPolicy:", encodedPutPolicy)
 
    /*官網文檔
    sign = hmac_sha1(encodedPutPolicy, "<SecretKey>")
    #假設 SecretKey 爲 MY_SECRET_KEY,實際簽名爲:
    sign = "c10e287f2b1e7f547b20a9ebce2aada26ab20ef2"
    注意:簽名結果是二進制數據,此處輸出的是每一個字節的十六進制表示,以便覈對檢查。
    */
    mac := hmac.New(sha1.New, []byte(SecretKey)) //坑點,順序跟說的不同???看了SDK才知道這樣弄,否則一直bad token
    mac.Write([]byte(encodedPutPolicy))
    //sign := fmt.Sprintf("%x\n", mac.Sum(nil))
    //encodeSign := base64.URLEncoding.EncodeToString([]byte(sign))
    digest := mac.Sum(nil) //坑點
 
    /*官網文檔
    encodedSign = urlsafe_base64_encode(sign)
    #最終簽名值爲:
    encodedSign = "wQ4ofysef1R7IKnrziqtomqyDvI="
    */
    encodeSign := base64.URLEncoding.EncodeToString(digest)
    fmt.Println("encodeSign:", encodeSign)
 
    /*官網文檔
    uploadToken = AccessKey + ':' + encodedSign + ':' + encodedPutPolicy
    #假設用戶的 AccessKey 爲 MY_ACCESS_KEY ,則最後獲得的上傳憑證應爲:
    uploadToken = "MY_ACCESS_KEY:wQ4ofysef1R7IKnrziqtomqyDvI=:eyJzY29wZSI6Im15LWJ1Y2tldDpzdW5mbG93ZXIuanBnIiwiZGVhZGxpbmUiOjE0NTE0OTEyMDAsInJldHVybkJvZHkiOiJ7XCJuYW1lXCI6JChmbmFtZSksXCJzaXplXCI6JChmc2l6ZSksXCJ3XCI6JChpbWFnZUluZm8ud2lkdGgpLFwiaFwiOiQoaW1hZ2VJbmZvLmhlaWdodCksXCJoYXNoXCI6JChldGFnKX0ifQ=="
    注意:爲確保客戶端、業務服務器和七牛服務器對於受權截止時間的理解保持一致,須要同步校準各自的時鐘。頻繁返回 401 狀態碼時請先檢查時鐘同步性與生成 deadline 值的代碼邏輯。
    */
    uploadToken := AccessKey + ":" + encodeSign + ":" + encodedPutPolicy
 
    form := map[string]string{"token": uploadToken, "key": "qiniuyun.go"}
    newfileUploadRequest("https://up-z2.qbox.me", form, "file", "./qiniuyun.go")
}
func newfileUploadRequest(uri string, form map[string]string, formFileName, path string) error {
    file, err := os.Open(path)
    if err != nil {
        return err
    }
    defer file.Close()
 
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    for key, val := range form {
        err = writer.WriteField(key, val)
        if err != nil {
            return err
        }
    }
    part, err := writer.CreateFormFile(formFileName, filepath.Base(path))
    if err != nil {
        return err
    }
    _, err = io.Copy(part, file)
    if err != nil {
        return err
    }
 
    err = writer.Close()
    if err != nil {
        return err
    }
    req, err := http.NewRequest("POST", uri, body)
    if err != nil {
        return err
    }
    req.Header.Set("Content-Type", writer.FormDataContentType())
    req.Header.Set("Host", "upload.qiniu.com")
    req.Header.Set("Content-Length", fmt.Sprint(body.Len()))
    fmt.Println("reqHeader:", req.Header)
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    Body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }
    fmt.Println("code:", resp.StatusCode, "\nheader:", resp.Header, "\n", string(Body))
    return nil
}
相關文章
相關標籤/搜索