Flask表单提交后,如何用JQuery实现文件下载完成后刷新页面?
问题描述
我有一个通过POST方法向Flask应用上传文件的页面,了解到Flask的路由无法同时处理send_file和redirect操作,所以目前的替代方案是在POST请求成功后刷新页面。
现有HTML代码
{% extends "base.html" %} {% block head %} <!-- {# <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/leaf.css') }}"> #} --> <script src="https://code.jquery.com/jquery-3.5.0.js"></script> <!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles/base.css') }}"> --> {% endblock %} {% block content %} <div id="vo_budget_file_settings"> {# <a href="/generatecleanbudgetfile" class="btn btn-primary">Upload Final CRO Budget File</a> #} <p>Please upload the final CRO budget File</p> <form class="" action="/generatecleanbudgetfile" method=POST enctype=multipart/form-data> <input type="file" name="data_file" accept=".xls, .xlsx, .xlsm"/> <input type="submit" value="Begin Format" onclick="loading();"/> </form> </div> <!-- funtion to show css spinner on button click --> <script type="text/javascript"> function loading(){ $(".loader").show(); } </script> <script type="text/javascript"> // Reload page 60 seconds after form submission $("vo_budget_file_settings").onsubmit = setTimeout(function () { window.location = "/bugetformatter"; }, 60000); console.log(window.location); </script> {% endblock %}
现有Flask应用代码
@app.route('/bugetformatter') def data_request_portal(): return render_template('CROBudgetFormatter.html', title='CRO Budget Formatting Tool') @app.route('/generatecleanbudgetfile', methods=['GET', 'POST']) def clean_budget(): file = request.files.get('data_file') app.logger.info('Conversion has started') try: if request.method == 'POST': file = request.files.get('data_file') file.seek(0) buffer = budget_cleaner(file) buffer.seek(0) app.logger.info('Conversion Complete') return send_file( buffer, as_attachment=True, attachment_filename=f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx', mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ) except: return render_template('error_type.html', title='Unable to process uploaded budget.')
核心疑问
有没有类似回调的脚本,能在请求完成且文件下载到浏览器后再重新加载页面?现在用60秒定时器刷新,但担心任务耗时超过60秒,想把刷新和文件下载绑定。
解决方案
可以通过AJAX异步上传文件,在后端返回文件数据后手动触发下载,完成后再执行页面刷新,精准控制刷新时机,摆脱定时器依赖。
步骤1:修改HTML表单与前端脚本
将原生表单提交改为AJAX提交,保留加载状态提示:
{% extends "base.html" %} {% block head %} <script src="https://code.jquery.com/jquery-3.5.0.js"></script> {% endblock %} {% block content %} <div id="vo_budget_file_settings"> <p>Please upload the final CRO budget File</p> <form id="upload-form" enctype=multipart/form-data> <input type="file" name="data_file" accept=".xls, .xlsx, .xlsm"/> <input type="button" value="Begin Format" onclick="handleUpload();"/> </form> </div> <script type="text/javascript"> function loading(){ $(".loader").show(); } function handleUpload() { loading(); const formData = new FormData(document.getElementById('upload-form')); $.ajax({ url: '/generatecleanbudgetfile', type: 'POST', data: formData, processData: false, contentType: false, xhrFields: { responseType: 'blob' // 以二进制blob格式接收文件 }, success: function(blob, status, xhr) { // 从响应头提取文件名 const contentDisposition = xhr.getResponseHeader('Content-Disposition'); let filename = 'stripped_budget.xlsx'; if (contentDisposition) { const matches = contentDisposition.match(/filename="?([^"]+)"?/); if (matches && matches[1]) { filename = matches[1]; } } // 创建临时链接触发浏览器下载 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); // 下载完成后立即刷新页面 window.location.href = "/bugetformatter"; }, error: function() { // 错误时跳转到错误页面 window.location.href = "/error_type"; }, complete: function() { // 可选:隐藏加载状态 $(".loader").hide(); } }); } </script> {% endblock %}
步骤2:调整Flask路由(优化原有逻辑)
原send_file逻辑无需大幅修改,补充错误状态码返回,让AJAX能正确识别错误:
from flask import request, send_file, render_template import datetime as dt @app.route('/bugetformatter') def data_request_portal(): return render_template('CROBudgetFormatter.html', title='CRO Budget Formatting Tool') @app.route('/generatecleanbudgetfile', methods=['POST']) def clean_budget(): app.logger.info('Conversion has started') try: file = request.files.get('data_file') if not file: raise ValueError("No file uploaded") file.seek(0) buffer = budget_cleaner(file) buffer.seek(0) app.logger.info('Conversion Complete') filename = f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx' return send_file( buffer, as_attachment=True, attachment_filename=filename, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ) except Exception as e: app.logger.error(f"Error processing file: {str(e)}") // 返回500错误码,触发AJAX的error回调 return render_template('error_type.html', title='Unable to process uploaded budget.'), 500
方案说明
- AJAX异步上传避免了页面跳转,可实时监听请求的成功/失败状态;
- 以
blob格式接收文件数据,手动创建下载链接触发浏览器下载,完全可控; - 下载完成后立即执行页面刷新,刷新时机与下载动作强绑定,不受任务耗时影响;
- 错误场景下会跳转到错误页面,同时可在
complete回调中处理加载状态的隐藏。
内容的提问来源于stack exchange,提问作者Mike Mann
相关产品推荐
相关产品推荐

