如何让带preventDefault的Ajax POST实现Flask文件上传?
Flask Ajax CSV文件上传失败问题排查与修复
问题场景
尝试通过Ajax将CSV文件上传至Flask服务器,已实现页面不刷新并弹出提示,但文件未实际上传成功。以下是原始复现代码:
app.py
import os.path from flask import Flask, render_template, request app = Flask(__name__, static_url_path='', static_folder='static', template_folder='templates') app.config['UPLOAD_FOLDER'] = './upload/' @app.route("/", methods=["POST", "GET"]) def home(): if request.method == "POST": f = request.files['todo'] f.save(os.path.join(app.config['UPLOAD_FOLDER'], 'upload.csv')) return 'this should not be printed' return render_template('index.html') if __name__ == '__main__': app.run(debug=True)
templates/index.html
<!DOCTYPE html> <html> <body> <form method="post" id="todo-form" enctype="multipart/form-data"> <input type="file" name="todo" id="todo"> <button type="submit">submit</button> </form> <script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script> <script src="test.js"></script> </body> </html>
static/ajax.js
$(document).on('submit', '#todo-form', function(e) { const fd = new FormData(this); e.preventDefault(); $.ajax({ type: 'POST', url: '/', data: fd, contentType: false, processData: false, complete: function() { alert('saved');}, }) });
问题根源
- JS文件引用不匹配:index.html中引用的是
test.js,但实际Ajax逻辑写在static/ajax.js中,导致上传的JS逻辑根本没有被加载执行,页面不刷新的现象可能是浏览器缓存或误操作导致的假象。 - 上传目录未自动创建:Flask不会自动生成上传目录,如果
./upload/不存在,f.save()会抛出IO异常,导致文件保存失败,且原代码未添加错误捕获,无法感知问题。 - 无明确反馈机制:仅使用
complete回调,无论上传成功或失败都会弹出提示,无法区分实际执行结果,不利于调试。
修复方案
1. 修正JS文件引用路径
修改templates/index.html中的JS引用:
<!-- 将原test.js改为正确的ajax.js路径 --> <script src="/ajax.js"></script>
2. 自动创建上传目录
在app.py中添加目录创建逻辑,避免因目录缺失导致的保存失败:
import os.path from flask import Flask, render_template, request app = Flask(__name__, static_url_path='', static_folder='static', template_folder='templates') app.config['UPLOAD_FOLDER'] = './upload/' # 自动创建上传目录,已存在则不报错 os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) @app.route("/", methods=["POST", "GET"]) def home(): if request.method == "POST": try: f = request.files['todo'] # 检查是否选择了文件 if f.filename == '': return '未选择文件', 400 f.save(os.path.join(app.config['UPLOAD_FOLDER'], 'upload.csv')) return '文件上传成功', 200 except Exception as e: return f'上传失败:{str(e)}', 500 return render_template('index.html') if __name__ == '__main__': app.run(debug=True)
3. 完善Ajax反馈逻辑
更新static/ajax.js,添加成功/错误回调,明确上传状态:
$(document).on('submit', '#todo-form', function(e) { const fd = new FormData(this); e.preventDefault(); $.ajax({ type: 'POST', url: '/', data: fd, contentType: false, processData: false, success: function(res) { alert('上传成功:' + res); }, error: function(xhr) { alert('上传失败:' + xhr.responseText); } }) });
内容的提问来源于stack exchange,提问作者cssstudent
相关产品推荐
相关产品推荐

