防微杜渐,未雨绸缪,百度网盘(百度云盘)接口API自动化备份上传以及开源发布,基于Golang1.18

news2024/12/27 22:10:13

奉行长期主义的开发者都有一个共识:对于服务器来说,数据备份非常重要,因为服务器上的数据通常是无价的,如果丢失了这些数据,可能会导致严重的后果,伴随云时代的发展,备份技术也让千行百业看到了其“云基因”的成长与进化,即基于云存储的云备份。

本次我们使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LINUX提权之信息收集篇

前言 准备开一个新坑,最近在学linux提权,于是打算用几篇文章来记录一下linux提权的重要知识点。首先第一篇文章介绍一下linux权限的基础信息以及如何进行信息收集。 LINUX权限简介 因为我们要学习权限提升,所以在学习提权之前我们先了解一…

ThinkPHP多语言文件包含RCE(QVD-2022-46174)

漏洞范围 v6.0.0<ThinkPHP<v6.0.13v5.0.0<ThinkPHP<5.0.12v5.1.0<ThinkPHP<5.1.8 需开启多语言选项&#xff0c;以thinkPHP6版本为例 在自定义中间件定义文件app/middleware.php中添加\think\middleware\LoadLangPack::class php需安装pearcmd拓展,并且开…

文档控件Aspose.words for.java 授权须知

支持的平台 Aspose.Words 可作为 .NET、Java、C 和 Python 的四种不同产品使用&#xff0c; .NET Framework.NET Standard 2.0Xamarin.AndroidXamarin.iOSXamarin.MacCOMMonoWindows Azure 系统要求 任何可以运行 Java Runtime Environment (JRE) 的操作系统都可以运行 Aspo…

02FPGA的巨大优势

在FPGA诞生的初期&#xff0c;计算机研究员是最先感受到FPGA的巨大优势的。 在此之前&#xff0c;要想实现一个新计算机体架构的设计想法&#xff0c;必须要开发一个ASIC作为原型&#xff0c;在面板上安装很多个体积庞大的IC。 但是&#xff0c;与这些需要投入巨大成本和精力…

I2C上拉电阻的选择-计算公式

I2C一般为开漏结构&#xff0c;需要在外部加上拉电阻&#xff0c;常见的阻值有1k、1.5k、2.2k、4.7k、5.1k、10k等。 但是应该如何根据开发要求选择合适的阻值呢&#xff1f; 假设SDA是低电平时&#xff0c;即MOS管导通。那么&#xff0c;就可以求出上拉电阻R的阻值。 上拉…

Lodop指定纸张类型不生效问题

根据官网指定纸张类型的样例 https://www.lodop.net/demolist/PrintSample5.html发现按以下代码各种打印机预览和打印效果均不同LODOPgetLodop();LODOP.PRINT_INIT("");LODOP.SET_PRINT_PAGESIZE(1,800,600,"");//设置纸张为80mm*60mmLODOP.ADD_PRINT_HTM(…

埋点成本治理实战(字节)

0、序言 随着业务的发展&#xff0c;业务上报的埋点数据会越来越多&#xff0c;杂乱的埋点数据不仅会消耗计算和存储成本&#xff0c;造成巨大的成本浪费&#xff0c;也无法有效的应用于业务&#xff0c;给业务带去数据价值&#xff0c;因此埋点数据的治理就很有必要。 一、治…

Redis缓存何以一枝独秀?(2) —— 聊聊Redis的数据过期、数据淘汰以及数据持久化的实现机制

大家好&#xff0c;又见面了。 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容&#xff0c;将会通过系列专题&#xff0c;讲清楚缓存的方方面面。如果感兴趣&#xff0c;欢迎关注以获取后续更新。 上一篇文章中呢&#xff0c;我们简单的介绍了下Redis的整体情…

Spring Security 表单配置(二)

Spring Security 表单配置&#xff08;二&#xff09;架构认证过滤器认证成功认证失败架构 Spring Security的整体架构&#xff0c;官网文档有介绍&#xff1a;https://docs.spring.io/spring-security/reference/5.7/servlet/architecture.html 友情提示&#xff1a;可以使用…

极客时间学习笔记:03芯片分类

芯片与集成电路的区别&#xff1f; 芯片肯定不全是集成电路。芯片里面&#xff0c;大约只有 80% 属于集成电路&#xff0c;其余的都是光电器件、传感器和分立器件&#xff0c;行业内把这些器件称为 O-S-D&#xff08;Optoelectronic, Sensor, Discrete&#xff09;。 下面这张…

SpringBoot 2.7.7入门案例

SpringBoot技术 文章目录SpringBoot技术SpringBoot介绍SpringBoot入门总结SpringBoot介绍 SpringBoot是为了简化搭建Spring项目过程而和开发的框架&#xff0c;Spring本身也是简化开发的框架技术。 可以想想SpringMVC项目&#xff08;整合SSM&#xff09;的开发过程&#xff…

【国信长天蓝桥杯】CT117E-M4 嵌入式开发板准备篇 ①开发环境搭建,Keil及STM32CubeMX的下载安装

摘要 本文章基于国信长天 CT117E-M4 嵌入式开发板&#xff0c;讲解了竞赛开发环境的搭建&#xff0c;Keil及STM32CubeMX软件的安装方法&#xff0c;祝各位同学蓝桥杯电子比赛取得好成绩! 软件下载 在蓝桥杯的嵌入式比赛中&#xff0c;主要用到两个软件&#xff0c;分别是代…

易烊千玺小网站短信验证码(小行星编号)发送和验证的实现

每次进入小网站都能看到小小的变化&#xff0c;反观易程序员背后维护的艰辛哈哈哈哈哈哈从此就多了一个目标&#xff1a;one day做出和易烊千玺一样牛的小网站这里面多多的知识点都是我目前都没有学会的&#xff08;明明都实训了。。页面设计 各种小图标动态效果 网站域名申请 …

【人工智能】观看人工智能 (AI) 入门课程,一起来看看都讲了什么

作者&#xff1a;小5聊 简介&#xff1a;一只喜欢全栈方向的程序员&#xff0c;欢迎咨询&#xff0c;尽绵薄之力答疑解惑 公众号&#xff1a;有趣小馆&#xff0c;一个有趣的关键词回复互动功能 1、课程介绍 1&#xff09;讨论什么是 AI 及其重要性 2&#xff09;简要介绍机器学…

MEmu Android Emulator

MEmu Android Emulator是一款专门用于游戏的软件模拟器。你可以从很多方面享受使用MEmu类软件的乐趣&#xff0c;让某人可以直接在计算机上安装它们。您不需要配置复杂的设置&#xff0c;只需安装它们即可。 您可以通过单击右侧的APK按钮轻松安装Andrew游戏。你想安装的APK游戏…

OPPO软件商店APP侵权投诉流程

目录一、官方指引二、侵权投诉流程1.侵权受理流程图2.受理渠道3.权利人侵权投诉通知邮件一、官方指引 https://open.oppomobile.com/new/developmentDoc/info?id10826 二、侵权投诉流程 1.侵权受理流程图 2.受理渠道 侵权处理邮箱&#xff1a;iprheytap.com 侵权处理抄送邮…

一,Spring入门

1 Spring简介 Spring是一个轻量级的JavaEE应用框架&#xff0c;对比EJB&#xff08;Enterprise Java Beans)技术是官方制定的重量级的JavaEE解决方案。EJB的重的表现&#xff1a;编码必须实现EJB内置的组件、必须部署在支持EJB的服务器中才能运行测试。EJB有很强的侵入性&…

ansible作业五

1、jinjia2模板 hosts.j2&#xff0c;内容如下(主机名和ip地址使用变量)&#xff1a; Welcome to 主机名 &#xff01;&#xff08;比如servera.lab.example.com&#xff09; My ip is ip地址. 要求在所有受管主机生成文件&#xff1a;/etc/welcome.txt。 2、角色部分 根据下列…

【Java|golang】2283. 判断一个数的数字计数是否等于数位的值

给你一个下标从 0 开始长度为 n 的字符串 num &#xff0c;它只包含数字。 如果对于 每个 0 < i < n 的下标 i &#xff0c;都满足数位 i 在 num 中出现了 num[i]次&#xff0c;那么请你返回 true &#xff0c;否则返回 false 。 示例 1&#xff1a; 输入&#xff1a;…

EXCEL的几个取整函数对比,int() round() ceiling() ceiling.math()等

1目标 我们处理EXCEL数据经常要遇到以下的需求 取整取倍数按任意数取倍数2 简单取整函数 int() int()只能最简单取整&#xff0c;无任何参数3 round() 四舍五入取整函数 & 整数位取整美化 round() roundup() rounddown() roundup() 和 rounddown() 除了向上和向下取整…