简体   繁体   English

从 html 上传文件<input>到 flask 服务器与 js

[英]Upload file from html <input> to flask server with js

I'm trying to send a file from a JS frontend to a Flask backend.我正在尝试将文件从 JS 前端发送到 Flask 后端。 But my flask backend seems to recieve no file.但是我的 flask 后端似乎没有收到文件。 It works when going on the flask backend HTML page and submiting manually, but I want the frontend to send the file to the backend.它在 flask 后端 HTML 页面上并手动提交时有效,但我希望前端将文件发送到后端。

Here's the javascript in question:这是有问题的 javascript:

function send() {
    const formData = new FormData();
    const files = document.getElementById("file");
    formData.append("file", files.files[0]);
    const requestOptions = {
        headers: {
            "Content-Type": "multipart/form-data",
        },
        mode: "no-cors",
        method: "POST",
        files: files.files[0],
        body: formData,
    };
    console.log(requestOptions);

    fetch("http://localhost:5000/upload", requestOptions).then(
        (response) => {
            console.log(response.data);
        }
    );
}

export default function App() {
    return (
        <div className="App" id="App">
            <header className="App-header">
                <Button variant="outlined" component="label" size="large">
                    Load Audio
                    <input
                        id="file"
                        type="file"
                        onChange={send}
                        hidden
                    />
                </Button>
            </header>
        </div>
    );
}

Here's the flask python script for handling incoming requests:这是用于处理传入请求的 flask python 脚本:

@app.route("/upload", methods=["GET", "POST"])
def upload():
    if request.method == 'POST':
        if 'file' not in request.files:
            print(1)
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            print(2)
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            print(3)
            filename = secure_filename(file.filename)
            session["id"] = filename
            file.save(os.path.join('UPLOAD', filename))
            return redirect(url_for('uploaded',
                                    filename=filename))

    return render_template('upload.html')

It prints 1, so no file is found.它打印 1,因此找不到文件。

In case it's useful, Here's a debug with print(request.headers) :如果它有用,这里有一个带有print(request.headers)的调试:

Host: localhost:5000
Connection: keep-alive
Content-Length: 412313
Sec-Ch-Ua: "Chromium";v="88", "Google Chrome";v="88", ";Not A Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Content-Type: multipart/form-data
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br

I read a lot online on how to uplaod file in that situation but i can't make it work.我在网上阅读了很多关于如何在这种情况下上传文件的信息,但我无法让它工作。 It would be great to have some help!能得到一些帮助会很棒!

Your file handling in Flask seems just right.您在 Flask 中的文件处理似乎恰到好处。 However, the way you specify your Content-Type header seems obscure to Flask.但是,您指定Content-Type header 的方式对 Flask 来说似乎很模糊。

While running a simplified example of your code, I tried testing it with cURL in the following way:在运行代码的简化示例时,我尝试通过以下方式使用 cURL 对其进行测试:

curl -XPOST http://localhost:5000/upload -F file=@TestFile.txt

This way Flask understood that a file has been uploaded, and I was able to see it in request.files :这样 Flask 就知道文件已上传,我可以在request.files中看到它:

ipdb> request.files
ImmutableMultiDict([('file', <FileStorage: 'TestFile.txt' ('text/plain')>)])

What also brought my attention is that the Content-Type has a boundary specified:同样引起我注意的是Content-Type有一个指定的边界

('Content-Type', 'multipart/form-data; boundary=------------------------aa8098f7b7fa6c61')

This makes me assume that specifying Content-Type: multipart/form-data manually doesn't seem to work.这让我假设手动指定Content-Type: multipart/form-data似乎不起作用。

Since you are trying to do the upload via JS fetch , consider looking here .由于您尝试通过 JS fetch进行上传,请考虑查看此处 They also don't recommend setting the header manually.他们也不建议手动设置 header。

I found another fix, which, as explained by @Icebreaker454, has to do with the content type.我发现了另一个修复,正如@Icebreaker454 所解释的,它与内容类型有关。

If the manually set Content-Type value does not match the actual content type of the file being uploaded, the request will fail.如果手动设置的 Content-Type 值与上传文件的实际内容类型不匹配,则请求会失败。 I fixed it by letting the file fill out that part for me:我通过让文件为我填写该部分来修复它:

function send() {
    const formData = new FormData();
    const files = document.getElementById("file");
    formData.append("file", files.files[0]);
    const requestOptions = {
        headers: {
            "Content-Type": files.files[0].contentType, // This way, the Content-Type value in the header will always match the content type of the file
        },
        mode: "no-cors",
        method: "POST",
        files: files.files[0],
        body: formData,
    };
    console.log(requestOptions);

    fetch("http://localhost:5000/upload", requestOptions).then(
        (response) => {
            console.log(response.data);
        }
    );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM