You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让带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');},
  })
});

问题根源

  1. JS文件引用不匹配:index.html中引用的是test.js,但实际Ajax逻辑写在static/ajax.js中,导致上传的JS逻辑根本没有被加载执行,页面不刷新的现象可能是浏览器缓存或误操作导致的假象。
  2. 上传目录未自动创建:Flask不会自动生成上传目录,如果./upload/不存在,f.save()会抛出IO异常,导致文件保存失败,且原代码未添加错误捕获,无法感知问题。
  3. 无明确反馈机制:仅使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:15:36