从前端JavaScript向 Python Flask后端上传Microsoft Excel文件时出现错误

前端开发 2026-07-09

我正试图把一个MS Excel文件从前端的JS上传到后端的Python Flask,带有 fetch-api。但我收到了下面的错误消息。我对使用AJAX或 JS的其他方式不太熟悉 xmlhttprequest

浏览器控制台错误

下面是我的HTML及 JS脚本:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <link rel="stylesheet" href="styles.css"> -->
</head>
<body>
    <h2>Upload a Document</h2>
    <!-- File Input -->
     <form method="POST">
        <input type="file" id="fileInput" accept=".xlsx, .xls">
        <button onclick="uploadDocument()"> Upload </button>
    </form>
    <p id="status"></p>
    <script>
        async function uploadDocument() {
            const fileInput = document.getElementById('fileInput');
            const status = document.getElementById('status');

            if (fileInput.files.length === 0) {
                status.innerText = "Please select a file first.";
                return;
            }

            // Create form data to hold the file
            const formData = new FormData();
            formData.append('file', fileInput.files[0]);

            try {
                // Send the file to the Flask backend
                const response = await fetch('http://127.0.0.1:6969/upload', {
                    method: 'POST',
                    body: formData
                });

                const result = await response.json();
                console.log(result)
                status.innerText = result.message || result.error;
            } catch (error) {
                status.innerText = "An error occurred during upload.";
                console.error(error);
            }
        }
    </script>

</body>
</html>

HTML文件是 docUpload.html

Python代码如下:

om flask import Flask, render_template, jsonify, request
from flask_cors import CORS, cross_origin
from waitress import serve
import pandas as pd
import os
from werkzeug.utils import secure_filename

app = Flask(__name__)
CORS(app)
app.config['UPLOAD_FOLDER'] = 'upload'

@app.route('/')
@cross_origin()
def index():
    return render_template("upload.html")

@app.route('/docUpload')
def addData():
     return render_template("docUpload.html")

@app.route('/upload', methods = ['POST'])  
def upload_excel():  
    if 'excel_file' not in request.files:
        return jsonify({"error": "no file uploaded"}), 400

    file = request.files['excel_file']

    if file.filename == '':
        return jsonify({"error": "No selected file"}),400

    filename = secure_filename(file.filename)
    dirname1 = os.path.dirname(__file__)
    patha = os.path.abspath(dirname1),app.CONFIG['UPLOAD_FOLDER'],filename
    os1 = os.path.join(patha)
    file.save(os1)

if __name__ == "__main__":
    serve(app, host='0.0.0.0', port=6969)

我不太确定自己哪里做错了。

解决方案

在用不同配置对代码进行测试后,我得出了与评论中的 @Herco相同的结论。

原始按钮仍然发送 <form>,但使用默认URL http://127.0.0.1:6969/
这会带来所有问题。
需要阻止按钮的默认行为。

一种方法是在按钮中使用 event.preventDefault()

<button onclick="event.preventDefault();uploadDocument(event)"> Upload </button>

更常见的方法是把 event 传给函数并在函数内部设定它

<button onclick="uploadDocument(event)"> Upload </button>

以及

function uploadDocument(event) {
    event.preventDefault();  // stop sending standard form

另一种方法是将按钮设置为不同的类型 type="button",而不是默认的 type="submit"

<button type="button" onclick="uploadDocument()"> Upload </button>

Flask代码还有其他错误。

在Flask中你期望在 request.files['excel_file'] 得到 excel_file
但在JavaScript中你发送的是 formData.append('file', fileInput.files[0]); 并包含 file
应该是

formData.append('excel_file', fileInput.files[0]);

os.path.join() 中你使用 tuple patha,但 join 需要分开的值。
可能需要使用 * 来解包它

os.path.join(*patha)

但更易读的做法是直接设置它

os.path.join(dirname, upload_folder, filename)

你有 app.configapp.CONFIG

保存文件后你仍然需要输出一些内容/JSON,例如

return jsonify({"message": "OK"})

用于测试的完整代码:

main.py

from flask import Flask, render_template, jsonify, request
from flask_cors import CORS, cross_origin
from waitress import serve
import pandas as pd
import os
from werkzeug.utils import secure_filename

app = Flask(__name__)
CORS(app)
app.config["UPLOAD_FOLDER"] = "upload"


@app.route("/")
@cross_origin()
def index():
    return render_template("upload.html")


@app.route("/docUpload")
def addData():
    return render_template("docUpload.html")


@app.route("/upload", methods=["POST"])
def upload_excel():
    print("upload")
    print(request.files)

    if "excel_file" not in request.files:
        return jsonify({"error": "no file uploaded"}), 400

    file = request.files["excel_file"]

    if file.filename == "":
        return jsonify({"error": "No selected file"}), 400

    dirname = os.path.abspath(os.path.dirname(__file__))
    upload_dir = app.config["UPLOAD_FOLDER"]
    filename = secure_filename(file.filename)

    os.makedirs(os.path.join(dirname, upload_dir), exist_ok=True)

    fullpath = os.path.join(dirname, upload_dir, filename)

    file.save(fullpath)

    return jsonify({"message": "OK"})


if __name__ == "__main__":
    PORT = 6969
    print(f"http://localhost:{PORT}")
    serve(app, host="0.0.0.0", port=PORT)
    # app.run(host="0.0.0.0", port=PORT, debug=True)

templates/upload.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <link rel="stylesheet" href="styles.css"> -->
</head>
<body>
    <h2>Upload a Document</h2>
    <hr>

    <h3>Pure HTML without JavaScript</h3>
    <!-- File Input -->
     <form method="POST" action="/upload" enctype="multipart/form-data">
        <input type="file" name="excel_file" accept=".xlsx, .xls">
        <button type="submit"> Upload </button>
    </form>
    <hr>

    <h3>With JavaScript</h3>
    <!-- File Input -->
     <form method="POST">
        <input type="file" id="fileInput" accept=".xlsx, .xls">
        <button type="button" onclick="uploadDocument(event)"> Upload </button><br>
        <button type="button" onclick="asyncUploadDocument(event)"> Async Upload </button><br>
        <button onclick="event.preventDefault();asyncUploadDocument()"> Event ; Async Upload </button>
    </form>
    <hr>

    <p id="status"></p>
    <hr>

    <script>
        function uploadDocument(event) {
            //event.preventDefault();  // stop sending standard form

            console.log("uploadDocument");

            const fileInput = document.getElementById('fileInput');
            const status = document.getElementById('status');

            console.log("fileInput.files.length:", fileInput.files.length)

            if (fileInput.files.length === 0) {
                status.innerText = "Please select a file first.";
                return;
            }

            console.log("create FormData");

            // Create form data to hold the file
            const formData = new FormData();
            formData.append('excel_file', fileInput.files[0]);

            const url = "http://localhost:6969/upload";
            // const url = "http://httpbingo.org/post";

            console.log("start fetch", url);

            // Send the file to the Flask backend
            fetch(url, {
                method: 'POST',
                body: formData
            })
            .then(
                response => response.json(),
                error => console.log("Wrong response without JSON")
            )
            .then(result => {
                console.log("response");
                console.log(result);
                status.innerText = result.message || result.error;
            })
            .catch(error => {
                status.innerText = "An error occurred during upload.";
                console.error(error);
            });
        }

        async function asyncUploadDocument(event) {
            //event.preventDefault();  // stop sending standard form

            console.log("asyncUploadDocument");

            const fileInput = document.getElementById('fileInput');
            const status = document.getElementById('status');

            console.log("fileInput.files.length:", fileInput.files.length)

            if (fileInput.files.length === 0) {
                status.innerText = "Please select a file first.";
                return;
            }

            console.log("create FormData");

            // Create form data to hold the file
            const formData = new FormData();
            formData.append('excel_file', fileInput.files[0]);

            const url = "http://localhost:6969/upload";
            // const url = "http://httpbingo.org/post";

            console.log("start fetch", url);

            try {
                // Send the file to the Flask backend
                const response = await fetch(url, {
                    method: 'POST',
                    body: formData
                })

                const result = await response.json();

                console.log("result");
                console.log(result);

                status.innerText = result.message || result.error;
            } catch (error) {
                 status.innerText = "An error occurred during upload.";
                 console.error(error);
            }
        }
    </script>

</body>
</html>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章