防微杜漸,未雨綢繆,百度網盤(百度雲盤)介面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
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...