1. 项目背景与核心需求
最近在帮朋友搭建一个轻量级的文件共享系统,需求很简单:通过网页上传文件到服务器,并能随时下载。这个场景其实在很多中小团队内部协作中都很常见——比如设计稿共享、文档版本管理或者临时文件交换。传统方案要么太重(比如Nextcloud),要么太简陋(直接FTP),于是决定自己用Python配合frp写个轻量级解决方案。
frp是个高性能的反向代理工具,特别适合没有公网IP的内网穿透场景。而Python的Flask框架可以快速搭建Web界面,两者结合正好满足需求。整个系统需要实现以下核心功能:
- 网页端文件上传(支持多文件、大文件)
- 文件列表展示与下载
- 简单的权限控制(至少要有上传密码)
- 通过frp实现外网访问
2. 技术方案设计
2.1 整体架构设计
系统采用经典的三层架构:
[浏览器] ←HTTP→ [frp服务端] ←隧道→ [frp客户端] ←HTTP→ [Flask应用] ←→ [文件存储]关键组件选型理由:
- Flask框架:相比Django更轻量,适合小型文件服务
- frp v0.38.0:稳定版本,支持TCP/HTTP两种穿透模式
- Bootstrap 5:快速构建美观的前端界面
- werkzeug.security:内置密码哈希工具
2.2 关键技术点
2.2.1 文件上传处理
使用Flask的request.files处理上传,特别注意:
@app.route('/upload', methods=['POST']) def upload(): if request.form.get('password') != config.UPLOAD_PWD: return "Invalid password", 403 for file in request.files.getlist('file'): if file.filename == '': continue filename = secure_filename(file.filename) file.save(os.path.join(UPLOAD_FOLDER, filename))2.2.2 frp穿透配置
服务端frps.ini关键配置:
[common] bind_port = 7000 vhost_http_port = 8080客户端frpc.ini配置示例:
[common] server_addr = your_server_ip server_port = 7000 [web] type = http local_port = 5000 custom_domains = your.domain.com3. 完整实现步骤
3.1 环境准备
服务端(有公网IP的VPS):
wget https://github.com/fatedier/frp/releases/download/v0.38.0/frp_0.38.0_linux_amd64.tar.gz tar -zxvf frp_0.38.0_linux_amd64.tar.gz客户端(本地运行Python的环境):
pip install flask python-dotenv
3.2 Flask应用开发
3.2.1 基础结构
# app.py from flask import Flask, render_template, request, send_from_directory import os from werkzeug.utils import secure_filename app = Flask(__name__) UPLOAD_FOLDER = 'uploads' app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB限制 if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER)3.2.2 路由实现
@app.route('/') def index(): files = os.listdir(app.config['UPLOAD_FOLDER']) return render_template('index.html', files=files) @app.route('/download/<filename>') def download(filename): return send_from_directory( app.config['UPLOAD_FOLDER'], filename, as_attachment=True )3.3 前端页面
<!-- templates/index.html --> <form method="post" enctype="multipart/form-data" action="/upload"> <input type="password" name="password" placeholder="Upload Password"> <input type="file" name="file" multiple> <button type="submit">Upload</button> </form> <ul> {% for file in files %} <li><a href="/download/{{ file }}">{{ file }}</a></li> {% endfor %} </ul>4. 部署与优化
4.1 frp服务端启动
./frps -c frps.ini4.2 本地运行
export FLASK_APP=app.py flask run --host=0.0.0.0 --port=50004.3 性能优化技巧
大文件上传:添加进度条显示
// 前端添加XMLHttpRequest进度事件监听 xhr.upload.onprogress = function(e) { if (e.lengthComputable) { var percent = Math.round((e.loaded / e.total) * 100); progressBar.style.width = percent + '%'; } };安全增强:
- 添加文件类型白名单
- 定期清理过期文件
- 使用HTTPS(通过frp的https2http功能)
5. 常见问题解决
5.1 上传失败排查
- 检查frp连接状态:
netstat -tulnp | grep frpc - 查看Flask日志:
tail -f /tmp/flask.log
5.2 性能问题
- 大文件上传超时:调整frp的
tcp_mux = false - 内存不足:限制单文件大小,添加流式处理
5.3 权限控制
建议的进阶方案:
# 在config.py中 DOWNLOAD_TOKENS = { "user1": "token1", "user2": "token2" } # 路由中添加验证 @app.route('/download/<filename>') def download(filename): token = request.args.get('token') if token not in config.DOWNLOAD_TOKENS.values(): abort(403) ...6. 扩展建议
- 数据库记录:使用SQLite记录文件元信息
- 分享链接:生成时效性下载链接
- API支持:添加RESTful接口供程序调用
- 日志审计:记录所有上传下载操作
这个方案在实际测试中,单台1核1G的VPS可以稳定支持20人团队的文件共享需求。对于更复杂的场景,可以考虑加入用户系统、文件预览等功能扩展。