个人名片
作者简介:java领域优质创作者
个人主页:码农阿豪
工作室:新空间代码工作室(提供各种软件服务)
个人邮箱:[[email protected]]
个人微信:15279484656
个人导航网站:www.forff.top
座右铭:总有人要赢。为什么不能是我呢?
码农阿豪系列专栏导航
面试专栏:收集了java相关高频面试题,面试实战总结️
Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用
Redis专栏:Redis从零到一学习分享,经验总结,案例实战
全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有
在开发Web应用时,文件处理和异常处理是常见的需求。特别是在使用Flask框架进行文件上传、处理和下载时,正确处理返回值类型和异常情况至关重要。本文将通过一个实际案例,分析如何优化Python Flask应用中的文件处理逻辑,并解决常见的异常问题。
在一个基于Flask的文件处理工具中,用户上传Excel文件,系统处理后返回结果文件。但在实际运行中,出现了以下错误:
AttributeError: 'list' object has no attribute 'read'
该错误表明,Flask的 send_file
方法期望接收一个文件路径(字符串),但实际传入的是一个列表(list
),导致无法读取文件内容。
此外,还出现了以下日志:
2025-05-20 01:05:37,500 - ERROR - process_and_export_results 返回了无效类型
这说明后端处理函数的返回值类型不符合预期,导致后续操作失败。
process_single_thread
函数返回的是 [output_file]
(包含单个文件路径的列表),但 send_file
需要的是 output_file
(字符串)。send_file
,导致 AttributeError
。process_single_thread
返回值原代码:
def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email):
# ...处理逻辑...
return [output_file] # 返回列表
优化后:
def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email):
"""单线程处理数据
Args:
raw_results: 待处理的原始数据列表
cookie: 用于处理的cookie
timestamp: 时间戳,用于生成文件名
base_filename: 基础文件名
receiver_email: 接收结果的邮箱地址
Returns:
str: 输出文件路径(直接返回字符串,而非列表)
"""
# ...处理逻辑...
return output_file # 直接返回字符串
优化点:
send_file
的预期。在 app.py
中,增加对返回值的检查:
try:
output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email)
# 检查返回值是否为有效路径
if not isinstance(output_file, str):
logger.error(f"无效返回值类型: {type(output_file)}")
return "处理错误:内部服务异常", 500
if not os.path.exists(output_file):
logger.error(f"文件不存在: {output_file}")
return "处理错误:结果文件未生成", 500
return send_file(output_file, as_attachment=True, download_name='result.xlsx')
except Exception as e:
logger.error(f"文件处理异常: {str(e)}", exc_info=True)
return f"处理错误:{str(e)}", 500
优化点:
FileNotFoundError
。在关键步骤添加详细日志,便于排查问题:
logger.info(f"开始处理文件: {filepath}")
logger.info(f"全国匹配模式: {'开启' if nationwide else '关闭'}")
logger.info(f"接收邮箱: {receiver_email}")
output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email)
logger.info(f"处理完成,输出文件: {output_file}")
deal_excel_file.py
(优化后)import os
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
def process_single_thread(raw_results, cookie, timestamp, base_filename, secretKey, receiver_email):
"""单线程处理数据,返回文件路径(字符串)"""
final_results = []
total_count = len(raw_results)
success_count = 0
for idx, item in enumerate(raw_results, 1):
record = process_single_item(item, idx, cookie, secretKey, False)
final_results.append(record)
if record["匹配状态"] == "成功":
success_count += 1
success_rate = (success_count / total_count) * 100 if total_count > 0 else 0
output_file = f"result_{timestamp}_{base_filename}.xlsx"
logger.info(
f"[{base_filename}] 处理完成 - 总数: {total_count}, "
f"成功: {success_count}, 失败: {total_count - success_count}, "
f"成功率: {success_rate:.2f}%"
)
export_to_excel(final_results, output_file)
if receiver_email:
try:
send_email_with_attachment(output_file, receiver_email)
logger.info(f"[{base_filename}] 结果已发送至邮箱: {receiver_email}")
except Exception as e:
logger.error(f"[{base_filename}] 邮件发送失败: {str(e)}")
return output_file # 直接返回字符串
app.py
(优化后)from flask import Flask, request, send_file
import os
import logging
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.FileHandler('app.log'), logging.StreamHandler()]
)
logger = logging.getLogger(__name__)
@app.route('/', methods=['POST'])
def upload_file():
try:
cookie = request.form.get('cookie', '').strip()
nationwide = request.form.get('nationwide') == '1'
receiver_email = request.form.get('email', '').strip()
logger.info(f"开始处理请求,Cookie: {cookie[:10]}...") # 避免日志泄露完整Cookie
if not cookie:
return "请提供有效的Cookie", 400
# 检查文件上传
if 'file' not in request.files:
return "未上传文件", 400
file = request.files['file']
if not file.filename.endswith('.xlsx'):
return "仅支持.xlsx文件", 400
# 保存上传文件
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
filepath = os.path.join(app.config['UPLOAD_FOLDER'], f'upload_{timestamp}.xlsx')
file.save(filepath)
# 处理文件
output_file = process_and_export_results(filepath, cookie, nationwide, receiver_email)
# 校验返回值
if not isinstance(output_file, str):
logger.error(f"无效的返回值类型: {type(output_file)}")
return "内部服务错误", 500
if not os.path.exists(output_file):
logger.error(f"文件不存在: {output_file}")
return "结果文件生成失败", 500
return send_file(output_file, as_attachment=True, download_name='result.xlsx')
except Exception as e:
logger.error(f"处理请求时出错: {str(e)}", exc_info=True)
return f"服务器错误: {str(e)}", 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
通过以上优化,系统能更稳定地处理文件,并提供清晰的错误信息,提升用户体验。