前言
上周末去隔壁老王家做吃饭,发现他整个人显得奇奇怪怪,一个人在书房里偷偷的做某件事,为了一探究竟,趁老王家媳妇儿不注意,捉个现行!!!
原来他痛恨某网盘已久,知道今天需要下载自己曾经上传的一个不可描述的文件时,需要发现下载 6 个多小时,于是他忍无可忍,决定用自己高价购买的服务器搭建一款简易版的个人网盘,我软磨硬泡的求老王把源码拷贝给我了。
安装依赖项
这是一款基于 Node.js
使用 fs
和 formidable
模块搭建个人网盘,fs
模块为 Node.js
内置模块,需要安装 formidable
模块
npm install formidable
服务
// 引用HTTP模块
const http = require("http");
// 引用fs模块
const fs = require('fs');
const url = require("url");
// 文件上传处理模块
const formidable = require('formidable');
// 创建服务
const server = http.createServer();
// 监听request事件
server.on("request", function(req, res) {
if (pathname == '/' && req.method == 'GET') {
fs.readFile("./index.html", "utf8", function(err, data) {
res.end(data);
})
} else if (req.method == 'GET') {
fs.readFile("." + pathname, function(err, data) {
res.end(data);
})
}
});
// 开启服务 端口号3000
server.listen(3000)
后台接口
fs 读取文件夹
else if (pathname == '/dir' && req.method == 'GET') {
fs.readdir("." + query.dir, (err, files) => {
if (err) {
console.log(err)
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
obj.data = files;
res.end(JSON.stringify(obj))
}
})
}
fs 判断是否为文件夹
else if (pathname == '/Selfile' && req.method == 'GET') {
fs.stat("." + query.dirname, (err, stats) => {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
obj.isDirectory = stats.isDirectory();
res.end(JSON.stringify(obj));
}
})
}
fs 创建文件夹
else if (pathname == '/AddDir' && req.method == 'GET') {
fs.mkdir("." + query.dirname, (err) => {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
res.end(JSON.stringify(obj))
}
})
}
fs 删除文件夹
else if (pathname == '/DelDir' && req.method == 'GET') {
fs.rmdir('.' + query.filename, function(err) {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
res.end(JSON.stringify(obj))
}
})
}
fs 删除文件
else if (pathname == '/DelFile' && req.method == 'GET') {
fs.unlink('.' + query.filename, function(err) {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
res.end(JSON.stringify(obj))
}
})
}
上传文件
else if (pathname == '/Update' && req.method == 'POST') { // 上传文件
// 处理上传的文件,保存到服务端指定位置
var form = new formidable.IncomingForm();
// 设置上传文件保存位置: 当前目录下的www文件夹
form.uploadDir = './www';
form.parse(req, function(err, fields, files) {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
// oldPath 保存的上传的名称
var oldPath = files.filetoupload.path;
console.log(oldPath)
// newPath 保存的路径
var newPath = form.uploadDir + '/' + files.filetoupload.name;
// 将上传的名称更改为原来的名称
fs.rename(oldPath, newPath, (err) => {
if (err) {
var obj = {};
obj.status = false;
res.end(JSON.stringify(obj))
} else {
var obj = {};
obj.status = true;
res.end(JSON.stringify(obj))
}
});
}
});
}
几个关键的 JS 逻辑
每做一次跳转,都需要保存每次文件夹的路径。
// 绑定双击事件
document.querySelectorAll('.oslist>div').forEach(ele => {
ele.ondblclick = () => {
// 如果当前为文件夹,双击点击进入文件夹。
if (ele.getAttribute('type') == 'file') {
// 设置请求的路径
root = RootHistory.data[RootHistory.index];
root += ('/' + ele.getAttribute('name'));
// 当回退后进入新的文件夹,旧的路径被删除
if (RootHistory.data.length > RootHistory.index + 1) {
RootHistory.data.length = RootHistory.index + 1;
}
// 历史记录
RootHistory.data.push(root);
RootHistory.index = RootHistory.data.length - 1;
// 获取目录
GetDir((arr) => {
view(arr);
}, root)
}
}
});
删除文件夹时需要递归每一个文件夹
// 创建递归函数删除文件
function recursion(dir) {
// dir为当前文件路径
isDirectory(e => {
// 如果是文件夹,判断文件夹是否为空
if (e) {
GetDir(e => {
// 如果是非空文件夹,则递归
if (e.length > 0) {
e.forEach(ele => {
return recursion(dir + "/" + ele);
})
} else {
// console.log('删除文件' + dir)
// 删除空文件夹
deleteDir(e => {
if (e.status) {
let newdir = dir.split('/');
newdir.pop();
// 禁止删除WWW目录值更目录
if (newdir.length > 2) {
newdir = newdir.join('/');
return recursion(newdir);
}
document.getElementById('refresh').click();
} else {
console.log('删除失败');
}
}, dir)
}
}, dir)
} else {
// 删除文件
deleteFile(e => {
if (e.status) {
console.log('删除成功');
document.getElementById('refresh').click();
} else {
console.log('删除失败')
}
}, dir)
}
}, dir)
}
上传文件需要使用 form 表单,使用 iframe 可以阻止页面跳转
<form action="Update" target="frame1" method="post" enctype="multipart/form-data" id="Update" style="display: none;">
<input type="file" name="filetoupload" id="filebtn">
</form>
<iframe name="frame1" frameborder="0" height="40"></iframe>
// 请求上传文件
function updateFile() {
var form = document.getElementById('Update');
form.submit();
}
在学习完成源码以后,我果断把文件放在我的学生主机上,只需要把端口打开就可以访问了,我将源码也一并放在了隔壁老王写的网盘里,Rabbit Yun 源码 点击下载,欢迎大家下载。由于服务器是学生主机,下载速度可能会很慢,(绝对比某网盘要快!!!)请谅解。