@@ -67,9 +67,9 @@ def _load_project_version() -> str:
6767static_dir = template_dir # 将static也指向templates目录
6868
6969app = Flask (__name__ , template_folder = template_dir , static_folder = static_dir )
70- # 启用 CORS
70+ # 启用 CORS,并暴露Content-Disposition头供前端JavaScript访问
7171# CORS(app, origins="http://localhost:5500") # 允许来自 http://localhost:5500 的请求
72- CORS (app , origins = "*" )
72+ CORS (app , origins = "*" , expose_headers = [ "Content-Disposition" ] )
7373
7474# 配置详细的日志
7575# 从环境变量获取日志目录,如果没有设置则使用默认位置
@@ -289,17 +289,26 @@ def process_file():
289289 download_name = original_filename ,
290290 mimetype = 'application/octet-stream'
291291 )
292- # 设置文件下载的响应头
292+ # 设置Content-Disposition,兼容所有浏览器
293+ # 参考: https://www.cnblogs.com/PengZhao-Mr/p/18489371
293294 try :
295+ # 检查文件名是否只包含ASCII字符
294296 original_filename .encode ('ascii' )
295297 response .headers ["Content-Disposition" ] = f'attachment; filename="{ original_filename } "'
298+ logger .info (f"文件名使用ASCII编码: { original_filename } " )
296299 except UnicodeEncodeError :
297- from urllib .parse import quote as url_quote
298- encoded_filename = url_quote (original_filename )
300+ # 包含中文,使用RFC 2231标准格式
301+ # filename*=UTF-8''编码后的文件名
302+ encoded_filename = quote (original_filename )
299303 response .headers ["Content-Disposition" ] = f"attachment; filename*=UTF-8''{ encoded_filename } "
304+ logger .info (f"设置UTF-8编码文件名: { encoded_filename } " )
305+
300306 response .headers ["Content-Type" ] = "application/octet-stream"
301307 response .headers ["X-Content-Type-Options" ] = "nosniff"
308+ # 确保前端JavaScript可以访问Content-Disposition头
309+ response .headers ["Access-Control-Expose-Headers" ] = "Content-Disposition"
302310 logger .info (f"返回文件: { original_filename } " )
311+ logger .info (f"Content-Disposition: { response .headers .get ('Content-Disposition' )} " )
303312 return response
304313 except Exception as e :
305314 logger .error (f"返回文件失败: { str (e )} \n { traceback .format_exc ()} " )
@@ -340,27 +349,26 @@ def process_file():
340349
341350 logger .info (f"返回ZIP文件: { safe_filename } " )
342351
343- # 手动构建响应,同时提供 filename 和 filename* 以支持各种浏览器
352+ # 手动构建响应
344353 response = make_response (memory_file .getvalue ())
345354 response .headers ['Content-Type' ] = 'application/zip'
346355
347- # 构建符合 RFC 6266 的 Content-Disposition 头
348- # 同时提供 ASCII 回退文件名和 UTF-8 编码文件名
356+ # 设置Content-Disposition,使用双格式兼容所有浏览器
349357 try :
350- # 尝试编码为 ASCII
358+ # 检查文件名是否只包含ASCII字符
351359 safe_filename .encode ('ascii' )
352- # 如果成功,使用简单格式
353360 response .headers ['Content-Disposition' ] = f'attachment; filename="{ safe_filename } "'
361+ logger .info (f"文件名使用ASCII编码: { safe_filename } " )
354362 except UnicodeEncodeError :
355- # 包含非 ASCII 字符,使用双格式
356- # filename 使用 ASCII 安全的回退名称
357- ascii_filename = f"output_{ datetime .now ().strftime ('%Y%m%d_%H%M%S' )} .zip"
358- # filename* 使用 RFC 2231 格式的 UTF-8 编码
363+ # 包含中文,使用RFC 2231标准格式
364+ # filename*=UTF-8''编码后的文件名
359365 encoded_filename = quote (safe_filename )
360- response .headers ['Content-Disposition' ] = (
361- f'attachment; filename="{ ascii_filename } "; '
362- f"filename*=UTF-8''{ encoded_filename } "
363- )
366+ response .headers ['Content-Disposition' ] = f"attachment; filename*=UTF-8''{ encoded_filename } "
367+ logger .info (f"设置UTF-8编码文件名: { encoded_filename } " )
368+
369+ # 确保前端JavaScript可以访问Content-Disposition头
370+ response .headers ['Access-Control-Expose-Headers' ] = 'Content-Disposition'
371+ logger .info (f"Content-Disposition已设置: { response .headers .get ('Content-Disposition' )} " )
364372
365373 return response
366374 except Exception as e :
0 commit comments