通过nodejs接入百度网盘开放平台实现上传文件
内容目录

由于想将服务器的内容备份一下,但是使用oos是要钱的(没钱),况且现在百度网盘是有会员的,所以就直接上传到百度网盘作为备份就可以了,使用nodejs实现

发现好多人都在找这个文章,放一个之前的代码链接供参考

luyuan/baiduwangpan: 百度网盘上传 – baiduwangpan – pplokijuhyg个人git站点 (theluyuan.com)

需要先获取token ,这个需要接入百度开放平台,因为不属于这里的讨论范畴,就不着重讨论,只重点讲解上传。

根据官网说明:需要实现预上传、分片上传、创建文件。只有完成这三步,才能将文件上传到网盘。

预上传

只要请求接口就要使用到一个库 axios 先安装axios

npm install axios

接口地址https://pan.baidu.com/rest/2.0/xpan/file?method=precreate

参数需要几

path是上传文件路径 在网盘里面的 需要进行编码 在node里面就是使用encodeURI()函数处理一下

size 这个是文件大小,下面将详细讨论如何在node中获取文件大小。

isdir 是不是文件或目录 0 是文件 1是目录 上传时选择对应的格式

autoinit 固定值1

rtype 重命名逻辑 注意下文档描述

block_list 重点,分片的md5,下面也会讲解如何获取分片

获取文件大小

fs.stat()这个函数在node中是获取文件信息 文档地址

先在全局设置分片大小 const size = 4 * 1024 * 1024

4mb 这是网盘规定的,而且第一个分片不支持小于4m

获取文件大小就是

return new Promise((res, e) => {
fs.stat("./a.exe", {}, (err, stats) => {
if (!err) {
daxiao = stats.size
let fenpian = Math.ceil(stats.size / size)
res({
size: daxiao,
num: fenpian
})
} else {
e("文件路径错误或文件不存在")
}
})
})

我封装了一个promise 然后返回是size就是大小 num就是分片数量

另一个重点是如何获取分片md5。

function getfile({ i, url }) {
return new Promise((res) => {
let data = '';
let start = i * size
let end = (i + 1) * size - 1
const stream = fs.createReadStream(url, {
start,
end
})
stream.on('data', (chunk) => {
// console.log(接收到 ${chunk.length} 个字节的数据);
if (!data) {
data = chunk
} else {
data = Buffer.concat([data, chunk])
}
});
stream.on('end', () => {
res(data)
});
})
}

这个函数是获取分片内容,根据上面的函数可以拿到一共有多少分片,然后就可以循环这个函数,传入第几个和文件地址,会返回buffer

burrefr不能进行相加,会转变成字符串,然后大小就不是之前的那样了,必须使用Buffer.concat

然后就是获取md5。

这里使用到了crypto

文档地址是 http://nodejs.cn/api/crypto.html#crypto_crypto_createhash_algorithm_options

const crypto = require('crypto');
async function getmd5list(url, info) {
promistlist = []
// fs.createReadStream
for (let i = 0; i < info.num; i++) {
let data = await getfile({ url, i })
const hash = crypto.createHash('md5'); // 创建一个md5加密的hash
hash.update(data); // 更新内容
const md5 = hash.digest('hex'); // 返回计算内容
console.log(md5);
promistlist.push(md5)
}
return promistlist
}

这就是计算md5的方法。

然后md5的列表就会被拿到了。

现在所有内容都拿完整了,下面就是预上传了。

开始预上传

拼接一下参数进行上传

async function precreate(info, url) {
let block_list = await getmd5list(url, info)
block_list = JSON.stringify(block_list)
let data = {
path: encodeURI('/app/服务器备份/baidu.exe'), //这是你的上传地址 需要进行url编码
size: info.size, //上传大小
isdir: 0, // 是不是文件夹 0 文件 1 文件夹
autoinit: 1,
block_list, // md5的list 注意按顺序
rtype: 1,
}
let str = "" // 这个需要拼接成formdata格式的,所以这面就手动拼接了
for (let i in data) {
str += ${i}=${data[i]}&
}
axios.post('https://pan.baidu.com/rest/2.0/xpan/file?method=precreate&access_token=这是你的token', str).then((res) => {
// 如果成功的话就是会返回 uploadid 和 block_list
// uplpadid就是下面上传的id block_list就是要上传的分片
upload({
url,
info,
uploadid: res.data.uploadid,
pian: res.data.block_list
})
})
}

到此预上传就完成了

下面就是上传分片了。

分片上传

async function upload({ url, info, uploadid, pian }) {
for (let i of pian) {
let data = await upgetfile({ url, i })
await uploadfile(i,data,uploadid) // 循环上传需要上传的分片
}
// https://pan.baidu.com/rest/2.0/xpan/file?method=create
// 下面的操作是上传完成合成文件
let data = {
path:encodeURI('/app/服务器备份/baidu.exe'), // 与上面那个一定要相同 而且还是需要url编码
size: daxiao, // 这个就是上传的大小,而且是总大小,不是分片的大小
isdir:0,
rtype: 1,
uploadid, // 这个就是上面返回的uploadid
block_list:JSON.stringify(promistlist) // 这个就是上传的MD5列表,还是全部的
}
let s = '' // 需要formdata格式
for(let i in data){
s += i + "=" + data[i] + '&'
}
console.log(s)
axios.post('https://pan.baidu.com/rest/2.0/xpan/file?method=create',s,{
params:{
access_token: '你的token',
}
}).then((res)=>{
console.log(res)
})
}

上面的uploadfile 是上传 下面的是拼接文件 不进行拼接文件是不能完成上传的。

function uploadfile(i,data,uploadid){
return new Promise((r)=>{
console.log(data.length)
let urls = '/rest/2.0/pcs/superfile2?' // 请求地址
let params = {
access_token: 'token', // 你的token
method: 'upload', // 默认
type: "tmpfile", // 默认
path: encodeURI('/app/服务器备份/baidu.exe'), //上传地址 与之前的相同
uploadid, //还是返回的uploadid
partseq: i // 这个是分片的编号
}
for (let j in params) {
urls += j + '=' + params[j] + '&'
}
// 下面由于我用axios上传失败了 改用httpsrequest
const options = {
hostname: 'd.pcs.baidu.com',
port: 443,
path: urls,
method: 'PUT', // 这面官网说是post 但是我试了下必须put 不然一直错
headers: {
'content-type':'multipart/form-data', //这是格式
'Content-Length': data.length // 这是主体长度
}
};
const req = https.request(options, (res) => {
console.log('状态码:', res.statusCode);
console.log('请求头:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
r(1)
});
req.on('error', (e) => {
console.error(e);
});
req.write(data); // 写入数据
req.end(); //写入完成一定要执行end
})
}

到现在为止就是上传成功了。

其实挺简单的,但是网上很少有nodejs的资料,如果你看到感觉还是有问题可以留言我继续完善,或者是加我qq

评论

  1. s
    seala
    2022-8-16
    2022-8-16 17:14:00

    36行的r(1) 是啥?

    • t
      博主
      seala
      2022-8-16
      2022-8-16 19:37:30

      promise 的成功回调

    • t
      博主
      seala
      2022-8-16
      2022-8-16 19:38:15

      可以尝试加下好友可以交流

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇