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

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

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

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

相关文章
|
4天前
|
人工智能 Linux API
PromptWizard:微软开源 AI 提示词自动化优化框架,能够迭代优化提示指令和上下文示例,提升 LLMs 特定任务的表现
PromptWizard 是微软开源的 AI 提示词自动化优化框架,通过自我演变和自我适应机制,迭代优化提示指令和上下文示例,提升大型语言模型(LLMs)在特定任务中的表现。本文详细介绍了 PromptWizard 的主要功能、技术原理以及如何运行该框架。
50 8
PromptWizard:微软开源 AI 提示词自动化优化框架,能够迭代优化提示指令和上下文示例,提升 LLMs 特定任务的表现
|
13天前
|
人工智能 自然语言处理 API
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
谷歌推出的Multimodal Live API是一个支持多模态交互、低延迟实时互动的AI接口,能够处理文本、音频和视频输入,提供自然流畅的对话体验,适用于多种应用场景。
61 3
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
|
8天前
|
前端开发 API 数据库
Next 编写接口api
Next 编写接口api
|
14天前
|
XML JSON 缓存
阿里巴巴商品详情数据接口(alibaba.item_get) 丨阿里巴巴 API 实时接口指南
阿里巴巴商品详情数据接口(alibaba.item_get)允许商家通过API获取商品的详细信息,包括标题、描述、价格、销量、评价等。主要参数为商品ID(num_iid),支持多种返回数据格式,如json、xml等,便于开发者根据需求选择。使用前需注册并获得App Key与App Secret,注意遵守使用规范。
|
13天前
|
JSON API 开发者
淘宝买家秀数据接口(taobao.item_review_show)丨淘宝 API 实时接口指南
淘宝买家秀数据接口(taobao.item_review_show)可获取买家上传的图片、视频、评论等“买家秀”内容,为潜在买家提供真实参考,帮助商家优化产品和营销策略。使用前需注册开发者账号,构建请求URL并发送GET请求,解析响应数据。调用时需遵守平台规定,保护用户隐私,确保内容真实性。
|
13天前
|
搜索推荐 数据挖掘 API
淘宝天猫商品评论数据接口丨淘宝 API 实时接口指南
淘宝天猫商品评论数据接口(Taobao.item_review)提供全面的评论信息,包括文字、图片、视频评论、评分、追评等,支持实时更新和高效筛选。用户可基于此接口进行数据分析,支持情感分析、用户画像构建等,同时确保数据使用的合规性和安全性。使用步骤包括注册开发者账号、创建应用获取 API 密钥、发送 API 请求并解析返回数据。适用于电商商家、市场分析人员和消费者。
|
23天前
|
JSON API 开发工具
淘宝实时 API 接口丨淘宝商品详情接口(Taobao.item_get)
淘宝商品详情接口(Taobao.item_get)允许开发者获取商品的详细信息,包括基本信息、描述、卖家资料、图片、属性及销售情况等。开发者需注册账号、创建应用并获取API密钥,通过构建请求获取JSON格式数据,注意遵守平台规则,合理使用接口,确保数据准确性和时效性。
|
24天前
|
JSON 缓存 监控
淘宝商品详情接口(Taobao.item_get)丨淘宝API接口指南
淘宝商品详情接口(Taobao.item_get)允许开发者通过HTTP GET方法获取淘宝商品的详细信息,包括商品ID、价格、库存等。请求需包含key、secret、num_iid等必选参数,支持缓存及多种返回格式。此接口广泛应用于电商数据分析、商品选品、价格监控等领域,提升商家运营效率。
|
24天前
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
111 5
|
28天前
|
JSON 搜索推荐 API
LAZADA关键词搜索API接口的获取与应用
Lazada作为东南亚领先的电商平台,为满足开发者和商户需求,开放了关键词搜索API接口。本文详细介绍该接口的获取与应用,助力提升电商业务效率。接口支持关键词搜索、指定搜索范围和排序方式,提供精准、灵活且全面的数据支持,促进电商应用和服务的优化与创新。
26 3