防微杜漸,未雨綢繆,百度網盤(百度雲盤)介面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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...