反应前端将图像发送到 fastapi 后端
React frontend sending image to fastapi backend
前端 = React,后端 = FastApi。
我怎样才能简单地从前端发送图像,并让后端将其保存到本地磁盘?
我尝试了不同的方法:在 object 中,在 base64 字符串中,等等。
但是我无法在 FastApi 中反序列化图像。
它看起来像一个编码字符串,我尝试将它写入文件或解码它,但没有成功。
const [selectedFile, setSelectedFile] = useState(null);
const changeHandler = (event) => {setSelectedFile(event.target.files[0]); };
const handleSubmit = event => {
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
body: formData2 // Also tried selectedFile
};
fetch('http://0.0.0.0:8000/task/upload_image/'+user_id, requestOptions)
.then(response => response.json())
}
return ( <div
<form onSubmit={handleSubmit}>
<fieldset>
<label htmlFor="image">upload picture</label><br/>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<br/>
<Button color="primary" type="submit">Save</Button>
</form>
</div>
);
和后端:
@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, request: Request):
body = await request.body()
# fails (TypeError)
with open('/home/backend/test.png', 'wb') as fout:
fout.writelines(body)
我也试着用这样的方式简单地模仿客户端:
curl -F media=@/home/original.png http://0.0.0.0:8000/task/upload_image/3
但结果相同...
----- [已解决] 为简单起见删除 user_id。
服务器部分必须如下所示:
@router.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
out_path = 'example/path/file'
async with aiofiles.open(out_path, 'wb') as out_file:
content = await file.read()
await out_file.write(content)
并且出于某种原因,客户端部分应该不在headers:
中包含content-type
function TestIt ( ) {
const [selectedFile, setSelectedFile] = useState(null);
const [isFilePicked, setIsFilePicked] = useState(false);
const changeHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
};
const handleSubmit = event => {
event.preventDefault();
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
//headers: { 'Content-Type': 'multipart/form-data' }, // DO NOT INCLUDE HEADERS
body: formData2
};
fetch('http://0.0.0.0:8000/task/uploadfile/', requestOptions)
.then(response => response.json())
.then(function (response) {
console.log('response')
console.log(response)
});
}
return ( <div>
<form onSubmit={handleSubmit}>
<fieldset>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<Button type="submit">Save</Button>
</form>
</div>
);
}
回复您的评论:是的,有一个简单的 JS-Fastapi 代码片段示例,不久前我已经回答了它。
您无法访问该文件的原因很简单:python 参数的命名必须与 formData 对象的键匹配。
相反,您访问的是原始请求,这没有意义。
只需更改您的 python 代码如下:
from fastapi import UploadFile, File
@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, file: UploadFile = File(...)):
# Your code goes here
官方文档里写的很详细
https://fastapi.tiangolo.com/tutorial/request-files/?h=file
仅供参考
以下是我回答的参考(实际检查过,我回答了多个与此主题相关的问题,应该足以了解上传文件时可能遇到的基本问题)
Uploading an excel file to FastAPI from a React app
前端 = React,后端 = FastApi。 我怎样才能简单地从前端发送图像,并让后端将其保存到本地磁盘? 我尝试了不同的方法:在 object 中,在 base64 字符串中,等等。 但是我无法在 FastApi 中反序列化图像。 它看起来像一个编码字符串,我尝试将它写入文件或解码它,但没有成功。
const [selectedFile, setSelectedFile] = useState(null);
const changeHandler = (event) => {setSelectedFile(event.target.files[0]); };
const handleSubmit = event => {
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' },
body: formData2 // Also tried selectedFile
};
fetch('http://0.0.0.0:8000/task/upload_image/'+user_id, requestOptions)
.then(response => response.json())
}
return ( <div
<form onSubmit={handleSubmit}>
<fieldset>
<label htmlFor="image">upload picture</label><br/>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<br/>
<Button color="primary" type="submit">Save</Button>
</form>
</div>
);
和后端:
@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, request: Request):
body = await request.body()
# fails (TypeError)
with open('/home/backend/test.png', 'wb') as fout:
fout.writelines(body)
我也试着用这样的方式简单地模仿客户端:
curl -F media=@/home/original.png http://0.0.0.0:8000/task/upload_image/3
但结果相同...
----- [已解决] 为简单起见删除 user_id。 服务器部分必须如下所示:
@router.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
out_path = 'example/path/file'
async with aiofiles.open(out_path, 'wb') as out_file:
content = await file.read()
await out_file.write(content)
并且出于某种原因,客户端部分应该不在headers:
中包含content-typefunction TestIt ( ) {
const [selectedFile, setSelectedFile] = useState(null);
const [isFilePicked, setIsFilePicked] = useState(false);
const changeHandler = (event) => {
setSelectedFile(event.target.files[0]);
setIsFilePicked(true);
};
const handleSubmit = event => {
event.preventDefault();
const formData2 = new FormData();
formData2.append(
"file",
selectedFile,
selectedFile.name
);
const requestOptions = {
method: 'POST',
//headers: { 'Content-Type': 'multipart/form-data' }, // DO NOT INCLUDE HEADERS
body: formData2
};
fetch('http://0.0.0.0:8000/task/uploadfile/', requestOptions)
.then(response => response.json())
.then(function (response) {
console.log('response')
console.log(response)
});
}
return ( <div>
<form onSubmit={handleSubmit}>
<fieldset>
<input name="image" type="file" onChange={changeHandler} accept=".jpeg, .png, .jpg"/>
</fieldset>
<Button type="submit">Save</Button>
</form>
</div>
);
}
回复您的评论:是的,有一个简单的 JS-Fastapi 代码片段示例,不久前我已经回答了它。
您无法访问该文件的原因很简单:python 参数的命名必须与 formData 对象的键匹配。
相反,您访问的是原始请求,这没有意义。
只需更改您的 python 代码如下:
from fastapi import UploadFile, File
@router.post("/upload_image/{user_id}")
async def upload_image(user_id: int, file: UploadFile = File(...)):
# Your code goes here
官方文档里写的很详细
https://fastapi.tiangolo.com/tutorial/request-files/?h=file
仅供参考
以下是我回答的参考(实际检查过,我回答了多个与此主题相关的问题,应该足以了解上传文件时可能遇到的基本问题)
Uploading an excel file to FastAPI from a React app