我正在尝试将文件从 JS 前端发送到 Flask 后端。 但我的烧瓶后端似乎没有收到文件。 当进入 Flask 后端 HTML 页面并手动提交时它可以工作,但我希望前端将文件发送到后端。
这是有问题的 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>
);
}
这是用于处理传入请求的 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')
打印 1,因此没有找到文件。
如果它有用,这是一个使用
print(request.headers)
进行的调试:
Host: localhost:5000
Connection: keep-alive
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
我在网上阅读了很多有关如何在这种情况下上传文件的信息,但我无法使其工作。 如果能得到一些帮助那就太好了!
Flask 中的文件处理似乎恰到好处。 然而,您指定
Content-Type
标头的方式对于 Flask 来说似乎很模糊。
在运行代码的简化示例时,我尝试通过以下方式使用 cURL 对其进行测试:
curl -XPOST http://localhost:5000/upload -F [email protected]
这样 Flask 就知道文件已上传,我就可以在
request.files
中看到它:
ipdb> request.files
ImmutableMultiDict([('file', <FileStorage: 'TestFile.txt' ('text/plain')>)])
还引起我注意的是
Content-Type
指定了边界:
('Content-Type', 'multipart/form-data; boundary=------------------------aa8098f7b7fa6c61')
这让我认为手动指定
Content-Type: multipart/form-data
似乎不起作用。
由于您正在尝试通过 JS 进行上传
fetch
,请考虑查看这里。他们也不建议手动设置标题。
我发现了另一个修复,正如 @Icebreaker454 所解释的,它与内容类型有关。
如果手动设置的Content-Type值与上传文件的实际内容类型不匹配,请求将会失败。我通过让文件为我填写该部分来修复它:
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);
}
);
}