前端
使用 XMLHttpRequest 通过发送 post 请求来发送文件给后端。
let xmlhttp = new XMLHttpRequest();
let fd = new FormData();
fd.append("file", pic_file);
fd.append("token", "tickle");
xmlhttp.open("POST", "http://127.0.0.1/files/");
xmlhttp.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36")
// xmlhttp.setRequestHeader("Content-Type", "multipart/form-data;");
// xmlhttp.setRequestHeader("Sec-Fetch-Site", "same-origin")
xmlhttp.send(fd);
后端
使用 fastapi 作为后端,接受文件。
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: UploadFile = File(), token: str = Form()
):
return {
"filename": file.filename,
"content_type": file.content_type,
"headers": file.headers,
"file": file.file,
"status": 1,
"token": token
}
遇到的问题
当前端设置了 Content-Type 头部字段时,无论值为什么,都会导致后端无法接收到文件,甚至无法响应请求,返回 400 Bad Request 错误。
其解决方法就是不在前端手动设置 Content-Type 字段,这样才可以正确传输文件,正确响应 post 请求。
其根本原因在于,FormData 需要使用 Content-Type: multipart/form-data; 头部字段,并在后面加上 FormData 的分界线内容,故需要的 Content-Type 的值为 "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryKhuQzAXRwwLQKgMf"。其中 boundary 为边界信息,内容是 ----WebKitFormBoundary 加一串长度为 16 字符的随机字符串。当请求中未设置该边界信息时,会导致 post 请求响应失败。
当我们不再前端中主动设置这一头部字段,浏览器会在发送 post 请求时自动添加该字段和边界信息,从而才能正确响应 post 请求。
总而言之
xhr 发送 post 请求的时候不要设置 Content-Type 字段。