一、基础文件上传实现
1.1 最小化上传示例
from flask import Flask, request
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return 'No file part', 400
    
    file = request.files['file']
    if file.filename == '':
        return 'No selected file', 400
    
    if file:
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        return 'File uploaded successfully', 200
1.2 前端表单示例
<form method="POST" enctype="multipart/form-data">
    <input type="file" name="file" accept=".pdf,.docx">
    <button type="submit">上传</button>
</form>
二、安全防护措施
2.1 文件验证机制
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
# 在视图函数中添加验证
if not allowed_file(file.filename):
    return 'Invalid file type', 415
2.2 进阶防护策略
| 防护类型 | 实现方式 | 示例代码 | 
|---|
| 文件头验证 | 检查文件魔数(Magic Number) | 使用 python-magic库 | 
| 大小限制 | 配置最大文件尺寸 | app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 | 
| 文件名安全 | 使用 secure_filename | from werkzeug.utils import secure_filename | 
| 病毒扫描 | 集成ClamAV | pyclamd库调用杀毒引擎 | 
三、企业级扩展方案
3.1 云存储集成(阿里云OSS示例)
from oss2 import Auth, Bucket
auth = Auth('<ACCESS_KEY>', '<SECRET_KEY>')
bucket = Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'bucket-name')
def upload_to_oss(file):
    try:
        result = bucket.put_object(
            f"uploads/{secure_filename(file.filename)}", 
            file
        )
        return result.status == 200
    except Exception as e:
        app.logger.error(f"OSS upload failed: {str(e)}")
        return False
3.2 数据库记录(Flask-SQLAlchemy)
class UploadedFile(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(120))
    size = db.Column(db.Integer)
    upload_time = db.Column(db.DateTime, default=datetime.utcnow)
    storage_path = db.Column(db.String(200))
def save_file_record(file):
    new_file = UploadedFile(
        filename=secure_filename(file.filename),
        size=os.path.getsize(file_path),
        storage_path=file_path
    )
    db.session.add(new_file)
    db.session.commit()
四、大文件处理优化
4.1 分片上传实现
// 前端分片处理(Web API)
const chunkSize = 5 * 1024 * 1024; // 5MB
let offset = 0;
while (offset < file.size) {
    const chunk = file.slice(offset, offset + chunkSize);
    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkNumber', chunkIndex);
    formData.append('totalChunks', Math.ceil(file.size / chunkSize));
    
    await fetch('/upload-chunk', {
        method: 'POST',
        body: formData
    });
    offset += chunkSize;
}
4.2 服务端分片合并
@app.route('/upload-chunk', methods=['POST'])
def upload_chunk():
    chunk = request.files['chunk']
    chunk_number = int(request.form['chunkNumber'])
    upload_id = request.form['uploadId']
    
    # 保存分片到临时目录
    temp_dir = os.path.join(app.config['UPLOAD_FOLDER'], upload_id)
    os.makedirs(temp_dir, exist_ok=True)
    
    chunk.save(os.path.join(temp_dir, str(chunk_number)))
    
    if chunk_number == int(request.form['totalChunks']) - 1:
        # 合并文件
        with open(final_path, 'wb') as f:
            for i in range(chunk_number + 1):
                with open(os.path.join(temp_dir, str(i)), 'rb') as cf:
                    f.write(cf.read())
        # 清理临时目录
        shutil.rmtree(temp_dir)
        return 'Upload complete', 200
    return 'Chunk received', 200