第35天-Flask文件上传全栈解决方案:从基础到企业级实践

一、基础文件上传实现

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_filenamefrom werkzeug.utils import secure_filename
病毒扫描集成ClamAVpyclamd库调用杀毒引擎

三、企业级扩展方案

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值