奉行长期主义的开发者都有一个共识:对于服务器来说,数据备份非常重要,因为服务器上的数据通常是无价的,如果丢失了这些数据,可能会导致严重的后果,伴随云时代的发展,备份技术也让千行百业看到了其“云基因”的成长与进化,即基于云存储的云备份。
本次我们使用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写入文件或者存入数据库,本文只讨论授权和上传逻辑,故不加入数据库的相关操作。
至此,百度网盘的授权操作就完成了。
服务器本地文件上传至百度网盘
说白了,有点像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.B