Flask 文件上传服务器 - 知识点总结
目录
- [Flask 框架基础](#Flask 框架基础)
- [HTTP 协议](#HTTP 协议)
- 文件与路径处理
- [Python 基础知识](#Python 基础知识)
- [Linux 权限管理](#Linux 权限管理)
- 服务器部署
1. Flask 框架基础
1.1 Flask 核心组件
| 组件 |
说明 |
Flask |
核心应用类,用于创建 Web 应用实例 |
request |
请求对象,用于获取客户端请求数据 |
jsonify() |
将 Python 对象转换为 JSON 响应 |
from flask import Flask, request, jsonify
app = Flask(__name__)
1.2 应用实例化
app = Flask(__name__)
__name__:Python 特殊变量,表示当前模块名称
- 直接运行脚本时:
__name__ == '__main__'
- 作为模块导入时:
__name__ 为模块名
- Flask 用它来确定应用的根目录
1.3 路由装饰器
@app.route('/path', methods=['GET', 'POST'])
def handler():
pass
- 将 URL 路径与 Python 函数绑定
- 支持多个装饰器指向同一函数(多路由)
methods 参数指定允许的 HTTP 方法
1.4 Flask 配置管理
app.config['KEY'] = value
app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024 # 500MB
app.config 是 Flask 的配置字典
- 可存储自定义配置项
- 支持通过配置文件或环境变量覆盖
2. HTTP 协议
2.1 常用 HTTP 方法
| 方法 |
说明 |
典型用途 |
GET |
获取资源 |
查询、列表 |
POST |
提交数据 |
文件上传、表单提交 |
DELETE |
删除资源 |
删除文件 |
2.2 Flask Request 对象
request.files # 获取上传文件 (字典)
request.form # 获取表单数据 (字典)
request.args # 获取 URL 参数 (字典)
request.json # 获取 JSON 请求体
2.3 文件上传格式
- 前端使用
multipart/form-data 格式
- Flask 通过
request.files 获取
- 返回
FileStorage 对象
2.4 HTTP 状态码
| 状态码 |
含义 |
使用场景 |
200 |
OK |
成功响应 |
400 |
Bad Request |
请求格式错误 |
404 |
Not Found |
资源不存在 |
413 |
Request Entity Too Large |
文件过大 |
500 |
Internal Server Error |
服务器内部错误 |
3. 文件与路径处理
3.1 os.path 模块
os.path.abspath(__file__) # 获取文件的绝对路径
os.path.dirname(path) # 获取目录部分
os.path.join(a, b) # 拼接路径(跨平台)
os.path.basename(path) # 获取文件名
os.path.splitext(path) # 分离文件名和扩展名
3.2 文件操作
os.listdir(path) # 列出目录内容
os.path.isfile(path) # 判断是否为文件
os.path.exists(path) # 判断路径是否存在
os.path.getsize(path) # 获取文件大小(字节)
os.path.getmtime(path) # 获取修改时间(时间戳)
os.remove(path) # 删除文件
os.makedirs(path) # 创建目录(递归)
3.3 FileStorage 对象
Flask/Werkzeug 提供的上传文件封装类,继承自 Python 的 io.IOBase:
from werkzeug.datastructures import FileStorage
file = request.files['file'] # 返回 FileStorage 对象
3.3.1 核心属性
| 属性 |
说明 |
示例 |
filename |
上传文件的原始文件名 |
"app-debug.apk" |
name |
表单字段名称 (name 属性) |
"file" |
content_type |
MIME 类型 |
"application/vnd.android.package-archive" |
content_length |
文件大小(字节) |
11507896 |
3.3.2 核心方法
| 方法 |
说明 |
返回值 |
save(destination) |
保存文件到磁盘 |
None |
read(size) |
读取文件内容 |
bytes |
stream |
文件数据流对象 |
FileStorage stream |
seek(offset) |
移动文件指针 |
None |
tell() |
获取当前指针位置 |
int |
close() |
关闭文件流 |
None |
3.3.3 使用示例
# 获取文件对象
file = request.files['file']
# 方式1:直接保存(推荐)
file.save(os.path.join(UPLOAD_FOLDER, file.filename))
# 方式2:读取内容后处理
content = file.read() # 读取全部内容
file.seek(0) # 重置指针
chunk = file.read(1024) # 分块读取
# 方式3:使用 stream 流式处理
with open(os.path.join(UPLOAD_FOLDER, file.filename), 'wb') as f:
while True:
chunk = file.stream.read(8192)
if not chunk:
break
f.write(chunk)
3.3.4 安全注意事项
# 1. 验证文件类型
ALLOWED_EXTENSIONS = {'apk', 'ipa', 'exe'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1]. in ALLOWED_EXTENSIONS
# 2. 防止路径遍历攻击
# 绝对禁止直接将用户输入的文件名拼接到路径
# 错误示例(危险!):
filename = request.files['file'].filename
os.path.join(UPLOAD_FOLDER, filename) # 用户可能传入 "../etc/passwd"
# 正确做法:使用安全文件名
from werkzeug.utils import secure_filename
filename = secure_filename(file.filename)
# 3. 限制文件大小
app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024
3.3.5 常见问题处理
# 问题1:文件名乱码
from werkzeug.utils import secure_filename
filename = secure_filename(file.filename)
# 问题2:文件已存在覆盖
# FileStorage.save() 默认覆盖,不提示
# 可添加检查:
import os
file_path = os.path.join(UPLOAD_FOLDER, file.filename)
if os.path.exists(file_path):
# 处理重复文件,如重命名
pass
# 问题3:大文件内存溢出
# 使用 stream 分块处理,避免 read() 一次性加载
3.4 时间戳转换
import time
timestamp = os.path.getmtime(path)
formatted = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp))
4. Python 基础知识
4.1 字符串格式化
# f-string (Python 3.6+)
name = "Alice"
f"Hello, {name}"
# 格式化数字
f"{size} bytes"
f"{size / 1024 / 1024:.2f} MB"
4.2 异常处理
try:
# 可能引发异常的代码
pass
except Exception as e:
# 捕获异常,e 是异常对象
print(f"Error: {e}")
finally:
# 无论是否异常都会执行
pass
4.3 主程序入口
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
__name__ == '__main__' 确保只在直接运行时执行
- 作为模块导入时不执行
4.4 运算符
'in' in dict_or_list # 成员运算符
not in # 不包含
4.5 列表操作
# 列表推导式
files = [{'name': f, 'size': os.path.getsize(f)} for f in filenames if os.path.isfile(f)]
# append 添加元素
files.append({'name': filename})
5. Linux 权限管理
5.1 权限表示法
八进制表示:
| 值 |
权限 |
二进制 |
| 0 |
--- |
000 |
| 1 |
--x |
001 |
| 2 |
-w- |
010 |
| 3 |
-wx |
011 |
| 4 |
r-- |
100 |
| 5 |
r-x |
101 |
| 6 |
rw- |
110 |
| 7 |
rwx |
111 |
5.2 常见权限组合
| 权限 |
八进制 |
说明 |
rwxr-xr-x |
755 |
所有者全部权限,其他人读和执行 |
rw-r--r-- |
644 |
所有者读写,其他人读 |
rwxrwxrwx |
777 |
所有人全部权限(谨慎使用) |
5.3 Python os.chmod()
import os
os.chmod(path, 0o755) # 设置权限(八进制)
os.chmod(path, 0o644) # 设置文件权限
5.4 权限作用对象
drwxr-xr-x
│││││││││
││││││││└─ 其他用户: 执行权限
│││││││└── 其他用户: 写权限
││││││└─── 其他用户: 读权限
│││││└──── 组用户: 执行权限
││││└───── 组用户: 写权限
│││└────── 组用户: 读权限
││└─────── 所有者: 执行权限
│└──────── 所有者: 写权限
└──────── 所有者: 读权限
d = 目录 (- = 文件)
6. 服务器部署
6.1 Flask 开发服务器
app.run(
host='0.0.0.0', # 监听所有接口
port=5000, # 端口号
debug=False # 调试模式
)
host='0.0.0.0':允许局域网访问
host='127.0.0.1':仅本地访问
debug=True:代码修改自动重启,显示详细错误
6.2 生产环境服务器
Flask 内置服务器不适合生产环境,推荐使用:
| 服务器 |
说明 |
| Gunicorn |
轻量级,推荐 Python WSGI 项目 |
| uWSGI |
功能强大,适合大型项目 |
| Nginx |
反向代理服务器 |
Gunicorn 示例:
gunicorn -w 4 -b 0.0.0.0:92 app:app
6.3 守护进程运行
# 使用 nohup 后台运行
nohup python app.py &
# 使用 systemd (推荐)
# /etc/systemd/system/upload.service
[Unit]
Description=Upload Server
After=network.target
[Service]
ExecStart=/usr/bin/python3 /path/to/app.py
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl start upload
sudo systemctl enable upload
附录:代码结构速查
upload_server.py
├── 导入模块
│ ├── flask.Flask
│ ├── flask.request
│ ├── flask.jsonify
│ └── os
│
├── 配置
│ ├── UPLOAD_FOLDER # 上传目录
│ ├── DIR_PERMISSIONS # 目录权限 0o755
│ ├── FILE_PERMISSIONS # 文件权限 0o644
│ └── MAX_CONTENT_LENGTH # 最大上传大小
│
├── 路由
│ ├── POST /upload # 上传文件
│ ├── GET /files # 文件列表
│ └── DELETE /delete/<file> # 删除文件
│
└── 启动
└── if __name__ == '__main__':
学习资源