Flask - 文件上传
Flask – 文件上传
Section titled “Flask – 文件上传”处理文件上传是 Web 应用程序的一个常见需求。Flask 使这一过程相对简单。
基本流程包括:
- 一个使用
method="POST"且关键在于使用enctype="multipart/form-data"的 HTML 表单。这种编码允许文件数据与表单一起发送。 - 表单中用于用户选择文件的
<input type="file" name="some_name">元素。 - 一个处理 POST 请求的 Flask 视图函数。
- 通过类似字典的
request.files对象访问上传的文件数据。 - 将文件安全地保存到服务器上的指定位置。
上传文件时,Flask(使用底层 Werkzeug 库)最初会将其保存到服务器上的临时位置。您的视图函数然后使用 HTML input 标签中指定的 name 属性(例如,request.files['file'])从 request.files 中检索此文件对象。
从 request.files 获得的 文件对象 有一个 save() 方法,您可以使用它来永久保存文件。在保存用户提供的文件名之前对其进行清理(sanitize)至关重要,以防止目录遍历攻击。Werkzeug 提供了 secure_filename() 函数用于此目的。它会从文件名中移除潜在有害的字符(例如 ../)。
您可以配置 Flask 以更有效地管理上传:
| 配置项 | 描述 |
|---|---|
app.config['UPLOAD_FOLDER'] | 上传文件应存储的目录路径。 |
app.config['MAX_CONTENT_LENGTH'] | 允许的最大文件大小,以字节为单位(例如,16 * 1024 * 1024 表示 16 MB)。Flask 将拒绝有效载荷(payload)更大的请求。 |
让我们创建一个简单的文件上传示例。
首先,是 HTML 表单 (templates/upload.html):
<!doctype html><html><head> <title>Upload File</title></head><body> <h2>Select a file to upload</h2> <form action="{{ url_for('handle_upload') }}" method="POST" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Upload"> </form></body></html>此表单将通过 POST 方法把选定的文件发送到与 handle_upload 视图函数关联的 URL。
现在,是 Flask 应用程序 (app.py):
import osfrom flask import Flask, render_template, request, redirect, url_for, flashfrom werkzeug.utils import secure_filename
# 定义上传文件的路径UPLOAD_FOLDER = 'uploads'# 定义允许的文件扩展名(可选,但建议用于安全)ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDERapp.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16 MB limitapp.config['SECRET_KEY'] = 'super-secret-key' # 用于闪现消息
# 确保上传文件夹存在if not os.path.exists(UPLOAD_FOLDER): os.makedirs(UPLOAD_FOLDER)
# 检查允许文件扩展名的辅助函数def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')def index(): # 重定向到上传表单页面 return redirect(url_for('show_upload_form'))
@app.route('/upload')def show_upload_form(): # 渲染包含上传表单的页面 return render_template('upload.html')
@app.route('/uploader', methods=['POST'])def handle_upload(): if 'file' not in request.files: flash('No file part in the request', 'danger') return redirect(request.url)
file = request.files['file']
if file.filename == '': flash('No selected file', 'warning') return redirect(url_for('show_upload_form'))
if file and allowed_file(file.filename): # 清理文件名 filename = secure_filename(file.filename) # 创建完整的保存路径 save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) try: file.save(save_path) flash(f'File "{filename}" uploaded successfully!', 'success') # 您可以重定向到显示已上传文件或成功消息的页面 return redirect(url_for('show_upload_form')) except Exception as e: flash(f'An error occurred while saving the file: {e}', 'danger') return redirect(url_for('show_upload_form')) elif file and not allowed_file(file.filename): flash('File type not allowed', 'danger') return redirect(url_for('show_upload_form')) else: # 理论上在上述检查后不会发生,但作为备用 flash('An unknown error occurred', 'danger') return redirect(url_for('show_upload_form'))
if __name__ == '__main__': app.run(debug=True)Python 代码中的关键点:
- UPLOAD_FOLDER: 定义文件保存的位置。
- ALLOWED_EXTENSIONS/allowed_file(): 基本验证,仅接受某些文件类型。这对于安全很重要。
- MAX_CONTENT_LENGTH: 限制上传文件大小。
- SECRET_KEY: Flask 用于闪现消息所必需。
- 文件夹创建: 确保上传目录存在。
handle_upload()函数:- 检查请求中是否存在文件部分 (
'file' in request.files)。 - 检查是否实际提交了文件名 (
file.filename == '')。 - 使用
allowed_file()检查文件类型是否允许。 - 使用
secure_filename()获取安全的文件名。 - 使用
os.path.join()构建完整路径。 - 调用
file.save()保存文件。 - 使用
flash()向用户提供反馈。 - 重定向回上传表单页面(或潜在的成功页面)。
要运行此示例,保存代码,创建一个名为 templates 的文件夹并在其中创建 upload.html 文件,然后运行 python app.py。在浏览器中访问 http://localhost:5000/(将重定向到 /upload)。您将看到文件输入框和提交按钮。选择一个文件(注意允许的扩展名和大小限制)并点击“Upload”。如果成功,文件将保存在 uploads 目录中(该目录创建在 app.py 所在文件夹),并显示一条成功消息。
重要安全注意事项:
- 切勿信任用户输入: 始终验证文件名 (
secure_filename) 和文件类型 (allowed_file)。如有必要,考虑更严格的检查,例如检查文件头(魔术数字)。 - 存储位置: 如果上传的文件不需要直接通过 Web 访问,请避免将其直接保存在 Web 应用程序的公共目录中。考虑使用一个独立的、非 Web 可访问的目录或云存储(例如 AWS S3、Google Cloud Storage)。
- 资源限制: 设置
MAX_CONTENT_LENGTH以防止通过巨大上传进行的拒绝服务攻击。 - 文件服务: 在将上传的文件提供给用户时务必小心,特别是如果它们包含可执行内容或 HTML/JavaScript。设置适当的
Content-Type头部,并可能设置Content-Disposition: attachment以强制下载。 - 权限: 确保 Web 服务器进程对
UPLOAD_FOLDER具有写入权限,但在其他地方仅具有最低限度的权限。