fastapi+使用dio和image_picker上载多个图像时,颤动422无法处理的实体
在Flutter Frontend上将多个图像与一些文本一起上传到Fastapi时,我会遇到422错误。我相信这与我的前端(颤音)有关,因为FastAPI上传端点在Swagger Docs UI localhost中起作用:8000/docs 。 我已经浏览了与此错误有关的所有堆栈流问题,并尝试在多部分添加标头和内容类型并仍然有错误。请有人告诉我我做错了什么? 下面是我的add_product.dart:
import 'dart:io';
import 'package:afia4/data/dio/dio_client.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
class AddProduct extends StatefulWidget {
const AddProduct({Key? key}) : super(key: key);
@override
State<AddProduct> createState() => _AddProductState();
}
class _AddProductState extends State<AddProduct> {
final formKey = GlobalKey<FormState>();
final productNameController = TextEditingController();
final productPriceController = TextEditingController();
final productDescriptionController = TextEditingController();
List<dynamic>? _product = [];
Dio dio = Dio();
final ImagePicker imagePicker = ImagePicker();
List<XFile>? imageFileList = [];
List<dynamic>? _images = [];
void selectImages() async {
final List<XFile>? selectedImages = await imagePicker.pickMultiImage();
if (selectedImages!.isNotEmpty) {
imageFileList!.addAll(selectedImages);
}
setState(() {});
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const Icon(Icons.close),
),
body: Form(
key: formKey,
child: Column(
children: [
const SizedBox(
height: 20,
),
productNameField(),
const SizedBox(
height: 20,
),
productPriceMethod(),
const SizedBox(
height: 20,
),
productDescriptionMethod(),
imageSelectionMethod(),
const SizedBox(
height: 20,
),
imagePreview(),
ElevatedButton(
onPressed: _uploadImage,
child: const Text("Upload images"),
),
],
),
));
}
_uploadImage() async {
for (int i = 0; i < imageFileList!.length; i++) {
var path = imageFileList![i].path;
_images!.add(await MultipartFile.fromFile(path,
filename: path.split('/').last,
contentType: MediaType("image", "jpg")));
var formData = FormData.fromMap(
{
// need to await for this async operation
"name": productNameController,
"price": productPriceController,
"description": productDescriptionController,
"image": _images,
},
);
var response = await DioClient.dio.post(
"http://10.0.2.2:8000/products/addProductFD",
data: formData,
options: Options(contentType: 'multipart/form-data'));
debugPrint(response.toString());
}
}
}
这是后端(fastapi)的途径,它运行良好:
@router.post('/addProductFD', status_code=status.HTTP_201_CREATED)
async def create(
name: str = Form(...),
price: float = Form(...),
description: str = Form(...),
files: List[UploadFile] = File(...),
db: Session = Depends(get_db),
# current_user: Vendor = Depends(get_current_active_user)
):
fileList = []
for file in files:
try:
FILEPATH = "./static/product_images/"
pimage_name = FILEPATH + imghex(file.filename)
contents = await file.read()
with open(pimage_name, 'wb') as f:
f.write(contents)
except Exception:
return {"message": "There was an error uploading the file(s)"}
finally:
await file.close()
fileList.append("localhost:8000" + pimage_name[1:])
file_urls = ",".join(fileList)
new_item = Product(
name=name,
price=price,
description=description,
imgs_url=[file_urls],
# owner_id=current_user.id
)
db.add(new_item)
db.commit()
db.refresh(new_item)
return new_item
这是Swaggerui或Postman的示例响应:
{
"name": "iPhone 44",
"price": 1800,
"is_active": true,
"imgs_url": [
"localhost:8000/static/product_images/0337698056d37da14fae.jpg,localhost:8000/static/product_images/db2f6998aa87a611c89e.jpg"
],
"id": 4,
"description": "Brand New with a fresh box.",
"owner_id": null
}
这是卷曲响应:
curl -X 'POST' \
'http://127.0.0.1:8000/products/addProductFD' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'name=iPhone 44' \
-F 'price=1800' \
-F 'description=Brand New with a fresh box.' \
-F '[email protected];type=image/jpeg' \
-F '[email protected];type=image/jpeg'
请在我的情况下如何修复此422?任何帮助将不胜感激。谢谢。
更多的颤音erros
I/Choreographer(10219): Skipped 34 frames! The application may be doing too much work on its main thread.
D/EGL_emulation(10219): app_time_stats: avg=259.93ms min=16.55ms max=592.22ms count=6
I/flutter (10219): {"detail":[{"loc":["body","price"],"msg":"value is not a valid float","type":"type_error.float"},{"loc":["body","files"],"msg":"field required","type":"value_error.missing"}]}
D/EGL_emulation(10219): app_time_stats: avg=47.31ms min=10.68ms max=340.63ms count=21
D/EGL_emulation(10219): app_time_stats: avg=500.29ms min=498.81ms max=501.77ms count=2
D/EGL_emulation(10219): app_time_stats: avg=500.14ms min=498.66ms max=501.04ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.88ms min=499.01ms max=504.05ms count=3
D/EGL_emulation(10219): app_time_stats: avg=498.13ms min=495.97ms max=500.18ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.05ms min=498.99ms max=501.57ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.46ms min=499.61ms max=501.69ms count=3
D/EGL_emulation(10219): app_time_stats: avg=499.81ms min=496.76ms max=501.59ms count=3
When uploading multiple images alongside some text to fastAPI from flutter frontend i encounter the 422 error. I believe it has to do with my frontend(flutter) because the fastAPI upload endpoint works in the swagger docs ui localhost:8000/docs.
I have looked through all the stackoverflow questions related to this error and tried adding a header and content type to the multipart and still having the error. PLease can someone tell me what i am doing wrong?
Below is my add_product.dart:
import 'dart:io';
import 'package:afia4/data/dio/dio_client.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
import 'package:image_picker/image_picker.dart';
class AddProduct extends StatefulWidget {
const AddProduct({Key? key}) : super(key: key);
@override
State<AddProduct> createState() => _AddProductState();
}
class _AddProductState extends State<AddProduct> {
final formKey = GlobalKey<FormState>();
final productNameController = TextEditingController();
final productPriceController = TextEditingController();
final productDescriptionController = TextEditingController();
List<dynamic>? _product = [];
Dio dio = Dio();
final ImagePicker imagePicker = ImagePicker();
List<XFile>? imageFileList = [];
List<dynamic>? _images = [];
void selectImages() async {
final List<XFile>? selectedImages = await imagePicker.pickMultiImage();
if (selectedImages!.isNotEmpty) {
imageFileList!.addAll(selectedImages);
}
setState(() {});
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const Icon(Icons.close),
),
body: Form(
key: formKey,
child: Column(
children: [
const SizedBox(
height: 20,
),
productNameField(),
const SizedBox(
height: 20,
),
productPriceMethod(),
const SizedBox(
height: 20,
),
productDescriptionMethod(),
imageSelectionMethod(),
const SizedBox(
height: 20,
),
imagePreview(),
ElevatedButton(
onPressed: _uploadImage,
child: const Text("Upload images"),
),
],
),
));
}
_uploadImage() async {
for (int i = 0; i < imageFileList!.length; i++) {
var path = imageFileList![i].path;
_images!.add(await MultipartFile.fromFile(path,
filename: path.split('/').last,
contentType: MediaType("image", "jpg")));
var formData = FormData.fromMap(
{
// need to await for this async operation
"name": productNameController,
"price": productPriceController,
"description": productDescriptionController,
"image": _images,
},
);
var response = await DioClient.dio.post(
"http://10.0.2.2:8000/products/addProductFD",
data: formData,
options: Options(contentType: 'multipart/form-data'));
debugPrint(response.toString());
}
}
}
This is the route for the backend(fastAPI) and it works well:
@router.post('/addProductFD', status_code=status.HTTP_201_CREATED)
async def create(
name: str = Form(...),
price: float = Form(...),
description: str = Form(...),
files: List[UploadFile] = File(...),
db: Session = Depends(get_db),
# current_user: Vendor = Depends(get_current_active_user)
):
fileList = []
for file in files:
try:
FILEPATH = "./static/product_images/"
pimage_name = FILEPATH + imghex(file.filename)
contents = await file.read()
with open(pimage_name, 'wb') as f:
f.write(contents)
except Exception:
return {"message": "There was an error uploading the file(s)"}
finally:
await file.close()
fileList.append("localhost:8000" + pimage_name[1:])
file_urls = ",".join(fileList)
new_item = Product(
name=name,
price=price,
description=description,
imgs_url=[file_urls],
# owner_id=current_user.id
)
db.add(new_item)
db.commit()
db.refresh(new_item)
return new_item
This is a sample response from the swaggerUI or postman:
{
"name": "iPhone 44",
"price": 1800,
"is_active": true,
"imgs_url": [
"localhost:8000/static/product_images/0337698056d37da14fae.jpg,localhost:8000/static/product_images/db2f6998aa87a611c89e.jpg"
],
"id": 4,
"description": "Brand New with a fresh box.",
"owner_id": null
}
This is the curl response:
curl -X 'POST' \
'http://127.0.0.1:8000/products/addProductFD' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F 'name=iPhone 44' \
-F 'price=1800' \
-F 'description=Brand New with a fresh box.' \
-F '[email protected];type=image/jpeg' \
-F '[email protected];type=image/jpeg'
Please how do i fix this 422 in my case? Any help will be appreciated. Thanks.
More FLutter erros
I/Choreographer(10219): Skipped 34 frames! The application may be doing too much work on its main thread.
D/EGL_emulation(10219): app_time_stats: avg=259.93ms min=16.55ms max=592.22ms count=6
I/flutter (10219): {"detail":[{"loc":["body","price"],"msg":"value is not a valid float","type":"type_error.float"},{"loc":["body","files"],"msg":"field required","type":"value_error.missing"}]}
D/EGL_emulation(10219): app_time_stats: avg=47.31ms min=10.68ms max=340.63ms count=21
D/EGL_emulation(10219): app_time_stats: avg=500.29ms min=498.81ms max=501.77ms count=2
D/EGL_emulation(10219): app_time_stats: avg=500.14ms min=498.66ms max=501.04ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.88ms min=499.01ms max=504.05ms count=3
D/EGL_emulation(10219): app_time_stats: avg=498.13ms min=495.97ms max=500.18ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.05ms min=498.99ms max=501.57ms count=3
D/EGL_emulation(10219): app_time_stats: avg=500.46ms min=499.61ms max=501.69ms count=3
D/EGL_emulation(10219): app_time_stats: avg=499.81ms min=496.76ms max=501.59ms count=3
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论