防微杜漸,未雨綢繆,百度網盤(百度雲盤)介面API自動化備份上傳以及開源發佈,基於Golang1.18

来源:https://www.cnblogs.com/v3ucn/archive/2023/01/11/17043144.html
-Advertisement-
Play Games

奉行長期主義的開發者都有一個共識:對於伺服器來說,數據備份非常重要,因為伺服器上的數據通常是無價的,如果丟失了這些數據,可能會導致嚴重的後果,伴隨雲時代的發展,備份技術也讓千行百業看到了其“雲基因”的成長與進化,即基於雲存儲的雲備份。 本次我們使用Golang1.18完成百度網盤(百度雲盤)介面AP ...


奉行長期主義的開發者都有一個共識:對於伺服器來說,數據備份非常重要,因為伺服器上的數據通常是無價的,如果丟失了這些數據,可能會導致嚴重的後果,伴隨雲時代的發展,備份技術也讓千行百業看到了其“雲基因”的成長與進化,即基於雲存儲的雲備份。

本次我們使用Golang1.18完成百度網盤(百度雲盤)介面API自動化備份上傳功能,以及演示如何將該模塊進行開源發佈。

百度網盤API接入授權

如果希望golang服務可以訪問並且上傳用戶的百度網盤,則需要經過用戶同意,這個流程被稱為“授權”。百度網盤開放平臺基於 OAuth2.0 接入授權。OAuth2.0 是一種授權協議,通過該協議用戶可以授權開發者應用訪問個人網盤信息與文件。

用戶同意授權後,開發者應用會獲取到一個 Access Token,該 Access Token 是用戶同意授權的憑證。開發者應用需要依賴 Access Token 憑證調用百度網盤公開API,實現訪問用戶網盤信息與授權資源。

基本流程和三方登錄差不多,需要跳轉百度網盤授權頁進行授權動作,隨後授權碼(code)會發送到回調網址,再用授權碼換取Access Token。但不一樣的是,百度官網提供一種相對簡單的獲取code方式,即oob,所謂oob就是直接線上請求後在表單中複製授權碼即可,不需要回調網址的參與。

首先根據官網文檔:https://pan.baidu.com/union/doc/ol0rsap9s 創建應用,創建好之後,將應用id拼接位oob授權網址:

https://openapi.baidu.com/oauth/2.0/authorize?client_id=你的應用id&response_type=code&redirect_uri=oob&scope=basic+netdisk

線上訪問複製授權碼:

註意授權碼一次性有效並且會在10分鐘後過期,隨後編寫代碼獲取token:

package bdyp  
  
import (  
	"fmt"  
	"net/http"  
	"net/url"  
)  
  
type Bcloud struct {  
	app_key      string  
	app_secret   string  
	accessToken  string  
	refreshToken string  
	logger       Logger  
}  
  
type tokenResp struct {  
	*Token  
	ErrorDescription string `json:"error_description"`  
}  
  
type Token struct {  
	AccessToken  string `json:"access_token"`  
	RefreshToken string `json:"refresh_token"`  
	ExpiresIn    int    `json:"expires_in"`  
}  
  
func (r *Bcloud) GetToken(code, redirectURI, app_key, app_secret string) (*Token, error) {  
	uri := fmt.Sprintf("https://openapi.baidu.com/oauth/2.0/token?"+  
		"grant_type=authorization_code&"+  
		"code=%s&"+  
		"client_id=%s&"+  
		"client_secret=%s&"+  
		"redirect_uri=%s",  
		url.QueryEscape(code),  
		url.QueryEscape(app_key),  
		url.QueryEscape(app_secret),  
		redirectURI)  
	resp := new(tokenResp)  
  
	err := r.requestJSON(http.MethodGet, uri, nil, resp)  
	if err != nil {  
		return nil, err  
	} else if resp.ErrorDescription != "" {  
		return nil, fmt.Errorf(resp.ErrorDescription)  
	}  
  
	r.app_key = app_key  
	r.app_secret = app_secret  
	r.accessToken = resp.AccessToken  
	r.refreshToken = resp.RefreshToken  
  
	return resp.Token, nil  
}

這裡分別創建網盤結構體和秘鑰結構體,通過官方介面將oob方式獲取的code交換token,分別為accessToken和refreshToken,refreshToken用於刷新 Access Token, 有效期為10年。

這裡最好將token寫入文件或者存入資料庫,本文只討論授權和上傳邏輯,故不加入資料庫的相關操作。

至此,百度網盤的授權操作就完成了。

伺服器本地文件上傳至百度網盤

根據官網文檔描述:https://pan.baidu.com/union/doc/3ksg0s9ye,上傳流程是指,用戶將本地文件上傳到百度網盤雲端伺服器的過程。文件上傳分為三個階段:預上傳、分片上傳、創建文件。第二個階段分片上傳依賴第一個階段預上傳的結果,第三個階段創建文件依賴第一個階段預上傳和第二階段分片上傳的結果,串列完成這三個階段任務後,本地文件成功上傳到網盤伺服器。

說白了,有點像HTTP連接的三次握手,目的就是為了保證上傳數據的完整性,強制串列的原子操作也有利於保證上傳任務的可靠性。

首先構建預上傳函數:

func (r *Bcloud) FileUploadSessionStart(req *FileUploadSessionStartReq) (*FileUploadSessionStartResp, error) {  
	token, err := r.getAuthToken()  
	if err != nil {  
		return nil, err  
	}  
  
	req.Method = "precreate"  
	req.AccessToken = token  
  
	req_, err := req.to()  
	if err != nil {  
		return nil, err  
	}  
  
	resp := new(FileUploadSessionStartResp)  
  
	err = r.requestURLEncode(http.MethodPost, "https://pan.baidu.com/rest/2.0/xpan/file", req_, resp)  
	if err != nil {  
		return nil, err  
	} else if err := resp.Err(); err != nil {  
		return nil, err  
	}  
  
	if len(resp.BlockList) == 0 {  
		resp.BlockList = []int64{0}  
	}  
  
	return resp, nil  
}

這裡參數為預上傳參數的結構體:

type FileUploadSessionStartReq struct {  
	Method      string `query:"method"`  
	AccessToken string `query:"access_token"`  
	Path        string `json:"path"`  
	File        io.Reader  
	RType       *int64 `json:"rtype"`  
}

隨後是分片上傳邏輯:

func (r *Bcloud) FileUploadSessionAppend(req *FileUploadSessionAppendReq) error {  
	token, err := r.getAuthToken()  
	if err != nil {  
		return err  
	}  
  
	req.Method = "upload"  
	req.AccessToken = token  
	req.Type = "tmpfile"  
  
	resp := new(fileUploadSessionAppendResp)  
  
	err = r.requestForm(http.MethodPost, "https://d.pcs.baidu.com/rest/2.0/pcs/superfile2", req, resp)  
	if err != nil {  
		return err  
	} else if err := resp.Err(); err != nil {  
		return err  
	} else if resp.ErrorMsg != "" {  
		return fmt.Errorf(resp.ErrorMsg)  
	}  
  
	return nil  
}  
  
type FileUploadSessionAppendReq struct {  
	Method      string    `query:"method"` // 本介面固定為precreate  
	AccessToken string    `query:"access_token"`  
	Type        string    `query:"type"`     // 固定值 tmpfile  
	Path        string    `query:"path"`     // 需要與上一個階段預上傳precreate介面中的path保持一致  
	UploadID    string    `query:"uploadid"` // 上一個階段預上傳precreate介面下發的uploadid  
	PartSeq     int64     `query:"partseq"`  // 文件分片的位置序號,從0開始,參考上一個階段預上傳precreate介面返回的block_list  
	File        io.Reader `file:"file"`      // 是		RequestBody參數	上傳的文件內容  
}

對於總體積大於4mb的文件,通過切片的方式進行上傳。

總後是合併文件寫入文件邏輯:

func (r *Bcloud) FileUploadSessionFinish(req *FileUploadSessionFinishReq) error {  
	token, err := r.getAuthToken()  
	if err != nil {  
		return err  
	}  
  
	req.Method = "create"  
	req.AccessToken = token  
  
	req_, err := req.to()  
	if err != nil {  
		return err  
	}  
  
	resp := new(fileUploadSessionFinishResp)  
  
	err = r.requestURLEncode(http.MethodPost, "https://pan.baidu.com/rest/2.0/xpan/file", req_, resp)  
	if err != nil {  
		return err  
	} else if err := resp.Err(); err != nil {  
		return err  
	}  
  
	return nil  
}  
  
type FileUploadSessionFinishReq struct {  
	Method      string    `query:"method"`  
	AccessToken string    `query:"access_token"`  
	Path        string    `json:"path"`  
	File        io.Reader `json:"-"`  
	UploadID    string    `json:"uploadid"`  
	RType       *int64    `json:"rtype"`  
}

至此,完成了文件上傳的三個階段:預上傳、分片上傳、創建文件。

開源發佈Publish

我們知道在 Golang的項目中,可以 import 一個托管在遠程倉庫的模塊,這個模塊在我們使用 go get 的時候,會下載到本地。既然是放在遠程倉庫上,意味著所有人都可以發佈,並且所以人也都可以使用,所以為了讓鄉親們更方便地上傳數據到百度網盤,讓我們把這個項目開源。

先在你的 Github 上新建一個倉庫,記得選 Public(公開項目),隨後將項目代碼推送到Github上面:

echo "# bdyp_upload_golang" >> README.md  
git init  
git add README.md  
git commit -m "first commit"  
git branch -M main  
git remote add origin https://github.com/zcxey2911/bdyp_upload_golang.git  
git push -u origin main

在項目根目錄使用go mod init 命令進行初始化,註意這裡的模塊名,填寫我們的git倉庫名稱,但是不要帶著.git:

go mod init github.com/zcxey2911/bdyp_upload_golang

再次推送項目模塊代碼:

git add -A  
git commit -m "Add a go mod file"
git push -u origin main

全部完成以後,刷新我們的倉庫,就可以看到我們的剛剛上傳的項目代碼了,點擊 release 發佈一個版本即可。

最後,通過go get命令安裝發佈之後的模塊:

go get github.com/zcxey2911/bdyp_upload_golang

完整的調用流程:

package main  
  
import (  
	"fmt"  
	bdyp "github.com/zcxey2911/bdyp_upload_golang"  
	"os"  
)  
  
func main() {  
  
	var bcloud = bdyp.Bcloud{}  
  
	// 獲取token  
	res, err := bcloud.GetToken("oob獲取的code", "oob", "應用appkey", "應用appsecret")  
  
	fmt.Println(res)  
  
	if err != nil {  
		fmt.Println("err", err)  
	} else {  
		fmt.Printf("介面的token是: %#v\n", res.AccessToken)  
	}  
	// 讀取文件  
	f, err := os.Open("/Users/liuyue/Downloads/ju1.webp")  
	if err != nil {  
		fmt.Println("err", err)  
		return  
	}  
	defer f.Close()  
  
	// 上傳文件  
	print(bcloud.Upload(&bdyp.FileUploadReq{  
		Name:  "/apps/雲盤備份/ju2.webp",  
		File:  f,  
		RType: nil,  
	}))  
  
}

查看上傳的數據:

簡單快速,一氣呵成。

結語

當然了百度雲盤備份也不是沒有缺陷,將數據存儲在雲端可能會存在安全性和隱私性問題,與此同時,數據量很大或者數據分佈在不同地點的情況下,恢複數據所需的時間會比較長。不差錢的同學也可以選擇磁碟快照服務,最後奉上項目地址,與君共勉:https://github.com/zcxey2911/bdyp_upload_golang


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題目傳送門 題意簡述 看到題目顯而易見是求逆序對個數。 思路分析 看到數據範圍 $x_i,y_i \le 2^{31}-1$,$k \le 10^5$。數據值域大但是個數少,且與數據之間的大小關係有關,因此考慮離散化。 離散化簡單介紹 離散化實際就是一種映射,當數據值域過大而個數有限時,可以嘗試離散 ...
  • Image模塊是PIL最基本的模塊,其中導出了Image類,一個Image類實例對象就對應了一副圖像。同時,Image模塊還提供了很多有用的函數。本文只是初步學習了一些用法與實際操作。 ...
  • 在 YARN 中,Application 是指應用程式,它可能啟動多個運行實例,每個運行實例由 —個 ApplicationMaster 與一組該 ApplicationMaster 啟動的任務組成,它擁有名稱、隊列、優先順序等屬性,是一個比較寬泛的概念,可以是一個 MepReduce 作業、一個 D... ...
  • 2023-01-10 一、MyBatis自動映射與自定義映射 1、自動映射: 在映射文件中使用的是“resultType”。指的是自動將資料庫中表的欄位與類中的屬性進行關聯映射。 2、自定義映射: (1)在映射文件中使用的是“resultMap”。一般是自動映射解決不了的問題,就使用自定義映射。 有 ...
  • 圖文並茂的內容往往讓人看起來更加舒服,如果只是文字內容的累加,往往會使讀者產生視覺疲勞。搭配精美的文章配圖則會使文章內容更加豐富,增加文章可讀性的同時,也能提升用戶體驗。但由於PDF文檔安全性較高,不易對其進行修改編輯,那我們要如何在PDF中插入、替換或刪除圖像呢?別擔心,今天為大家介紹一種高效便捷... ...
  • 一、前言 今天小編帶大家一起整合一下easyExcel,之所以用這個,是因為easyExcel性能比較好,不會報OOM! 市面上常見的導入導出Excel分為三種: hutool easyExcel poi hutool和easyExcel都是對poi的封裝,使用起來更加方便! 如果想使用poi和hu ...
  • 一、前言”前後端分離“已經成為互聯網項目開發的業界標桿,通過Tomcat+Ngnix(也可以中間有個Node.js),有效地進行解耦。並且前後端分離會為以後的大型分散式架構、彈性計算架構、微服務架構、多端化服務(多種客戶端,例如:瀏覽器,車載終端,安卓,IOS等等)打下堅實的基礎。前後端分離(解耦) ...
  • 1、在任意目錄之間快速移動 你發現自己要在兩個或更多目錄之間頻繁移動,一會切換到這裡,一會切換到那裡,來回跳轉。這些目錄之間隔得還挺遠,反覆輸入冗長的路徑讓人疲憊不堪。 使用內建命令 pushd 和 popd 來管理目錄棧,輕鬆地在目錄之間切換。下麵是一個簡單的示例: $ cd /tmp/tank ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...