Flutter 没有在 post 请求的多部分中附加图像
Flutter not attaching image in multipart for post request
你好,我正在尝试创建一个非常基本的 flutter 应用程序,它从我的桌面拍摄照片并通过 HTTP.POST(作为多部分文件)将其发送到我的服务器。我一直在使用 dio
来尝试这个,但出于某种原因,我的服务器一直显示 'image' is not present
。我尝试调试 post 代码,图像显示在日志中(base64 等)。我在 PostMan 中尝试了这个并且我成功了,虽然随着颤动我得到一个 POST http://localhost:8080/event/test 500
说 Required request part 'image' is not present
.
这是我尝试使用的图像:
这是我测试过的一些数据是否为空或无效的数据,在我创建 FormData 后它似乎恢复有效:
print(formData.fields.last.key); // image
print(formData.fields.last.value); // Instance of 'MultipartFile'
print(formData.fields.last.value.length); // 27
print(formData.fields.last.value.isEmpty); // false
这是我的 flutter 代码:
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
FilePickerCross filePickerCross;
String _fileString = '';
Set<String> lastFiles;
FileQuotaCross quota = FileQuotaCross(quota: 0, usage: 0);
@override
void initState() {
FilePickerCross.listInternalFiles()
.then((value) => setState(() => lastFiles = value.toSet()));
FilePickerCross.quota().then((value) => setState(() => quota = value));
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blueGrey, accentColor: Colors.lightGreen),
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Text(
'Last files',
style: Theme.of(context).textTheme.headline5,
),
(lastFiles == null)
? Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
shrinkWrap: true,
primary: false,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => ListTile(
leading: Text('$index.'),
title: Text(lastFiles.toList()[index]),
onTap: () async => setFilePicker(
await FilePickerCross.fromInternalPath(
path: lastFiles.toList()[index])),
),
itemCount: lastFiles.length,
),
RaisedButton(
onPressed: _selectFile,
child: Text('Open File...'),
),
(filePickerCross == null)
? Text('Open a file first, to save')
: RaisedButton(
onPressed: _selectSaveFile,
child: Text('Save as...'),
),
Text(
'File system details',
style: Theme.of(context).textTheme.headline5,
),
Text('Quota: ${(quota.quota / 1e6).round()} MB'),
Text(
'Usage: ${(quota.usage / 1e6).round()}; Remaining: ${(quota.remaining / 1e6).round()}'),
Text('Percentage: ${quota.relative.roundToDouble()}'),
Text(
'File details',
style: Theme.of(context).textTheme.headline5,
),
Text(
'File path: ${filePickerCross?.path ?? 'unknown'} (Might cause issues on web)\n'),
Text('File length: ${filePickerCross?.length ?? 0}\n'),
Text('File as String: $_fileString\n'),
],
),
),
);
}
void _selectFile() {
FilePickerCross.importFromStorage()
.then((filePicker) => setFilePicker(filePicker));
}
void _selectSaveFile() {
filePickerCross.exportToStorage();
}
setFilePicker(FilePickerCross filePicker) => setState(() {
filePickerCross = filePicker;
filePickerCross.saveToPath(path: filePickerCross.fileName);
FilePickerCross.quota().then((value) {
print(value);
setState(() => quota = value);
});
lastFiles.add(filePickerCross.fileName);
try {
_fileString = filePickerCross.toString();
} catch (e) {
_fileString = 'Not a text file. Showing base64.\n\n' +
filePickerCross.toBase64();
Upload(filePickerCross);
}
});
Future<void> Upload(FilePickerCross file) async {
Dio dio = new Dio();
try{
FormData formData = new FormData.fromMap({"image":
file.toMultipartFile()});
print(formData.fields.last.key);
print(formData.fields.last.value);
print(formData.fields.last.value.length);
print(formData.fields.last.value.isEmpty);
Response response = await dio.post("http://localhost:8080/event/test",data:formData, options: Options(
headers: {
"accept" : "*/*",
// "Authorization" : "TOKEN",
"Content-Type" : "multipart/form-data",
}
));
print(response);
print("d");
}catch(e){
}
}
}
这就是我厌烦的 Post 男人:
最后这是我的服务器代码:
@PostMapping(value = "/test")
@ApiOperation(value = "add an event data via the body ")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = ResponseModel.class)})
public ResponseEntity<?> post(@RequestPart("image") MultipartFile image) {
ResponseModel responseModel;
System.out.println(image.getName());
int responseNumber = 0;
String res = response(responseNumber);
if (responseNumber != 0) {
responseModel = new ResponseModel(false, responseNumber, res);
} else {
responseModel = new ResponseModel(true, responseNumber, res);
}
return new ResponseEntity<>( responseModel, HttpStatus.OK);
}
原来你需要实现 web 有点不同,见下文:
Future<String> makeRequest() async {
var url = Uri.parse(
"http://localhost:8080/event/");
var request = new http.MultipartRequest("POST", url);
EventResource eventResource = new EventResource();
//Created and added values to eventResource
var body = jsonEncode(eventResource);
request.files.add(await http.MultipartFile.fromBytes('image', _selectedFile,
contentType: new MediaType('application', 'octet-stream'),
filename: name));
request.files.add(await http.MultipartFile.fromString('body', body,
contentType: new MediaType('application', 'json'),
));
request.headers['Content-Type'] = "application/json";
request.headers['Authorization'] = "SOME_JWT";
request.send().then((response) {
print(response.statusCode);
});
你好,我正在尝试创建一个非常基本的 flutter 应用程序,它从我的桌面拍摄照片并通过 HTTP.POST(作为多部分文件)将其发送到我的服务器。我一直在使用 dio
来尝试这个,但出于某种原因,我的服务器一直显示 'image' is not present
。我尝试调试 post 代码,图像显示在日志中(base64 等)。我在 PostMan 中尝试了这个并且我成功了,虽然随着颤动我得到一个 POST http://localhost:8080/event/test 500
说 Required request part 'image' is not present
.
这是我尝试使用的图像:
这是我测试过的一些数据是否为空或无效的数据,在我创建 FormData 后它似乎恢复有效:
print(formData.fields.last.key); // image
print(formData.fields.last.value); // Instance of 'MultipartFile'
print(formData.fields.last.value.length); // 27
print(formData.fields.last.value.isEmpty); // false
这是我的 flutter 代码:
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:file_picker_cross/file_picker_cross.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
FilePickerCross filePickerCross;
String _fileString = '';
Set<String> lastFiles;
FileQuotaCross quota = FileQuotaCross(quota: 0, usage: 0);
@override
void initState() {
FilePickerCross.listInternalFiles()
.then((value) => setState(() => lastFiles = value.toSet()));
FilePickerCross.quota().then((value) => setState(() => quota = value));
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blueGrey, accentColor: Colors.lightGreen),
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Text(
'Last files',
style: Theme.of(context).textTheme.headline5,
),
(lastFiles == null)
? Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
shrinkWrap: true,
primary: false,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => ListTile(
leading: Text('$index.'),
title: Text(lastFiles.toList()[index]),
onTap: () async => setFilePicker(
await FilePickerCross.fromInternalPath(
path: lastFiles.toList()[index])),
),
itemCount: lastFiles.length,
),
RaisedButton(
onPressed: _selectFile,
child: Text('Open File...'),
),
(filePickerCross == null)
? Text('Open a file first, to save')
: RaisedButton(
onPressed: _selectSaveFile,
child: Text('Save as...'),
),
Text(
'File system details',
style: Theme.of(context).textTheme.headline5,
),
Text('Quota: ${(quota.quota / 1e6).round()} MB'),
Text(
'Usage: ${(quota.usage / 1e6).round()}; Remaining: ${(quota.remaining / 1e6).round()}'),
Text('Percentage: ${quota.relative.roundToDouble()}'),
Text(
'File details',
style: Theme.of(context).textTheme.headline5,
),
Text(
'File path: ${filePickerCross?.path ?? 'unknown'} (Might cause issues on web)\n'),
Text('File length: ${filePickerCross?.length ?? 0}\n'),
Text('File as String: $_fileString\n'),
],
),
),
);
}
void _selectFile() {
FilePickerCross.importFromStorage()
.then((filePicker) => setFilePicker(filePicker));
}
void _selectSaveFile() {
filePickerCross.exportToStorage();
}
setFilePicker(FilePickerCross filePicker) => setState(() {
filePickerCross = filePicker;
filePickerCross.saveToPath(path: filePickerCross.fileName);
FilePickerCross.quota().then((value) {
print(value);
setState(() => quota = value);
});
lastFiles.add(filePickerCross.fileName);
try {
_fileString = filePickerCross.toString();
} catch (e) {
_fileString = 'Not a text file. Showing base64.\n\n' +
filePickerCross.toBase64();
Upload(filePickerCross);
}
});
Future<void> Upload(FilePickerCross file) async {
Dio dio = new Dio();
try{
FormData formData = new FormData.fromMap({"image":
file.toMultipartFile()});
print(formData.fields.last.key);
print(formData.fields.last.value);
print(formData.fields.last.value.length);
print(formData.fields.last.value.isEmpty);
Response response = await dio.post("http://localhost:8080/event/test",data:formData, options: Options(
headers: {
"accept" : "*/*",
// "Authorization" : "TOKEN",
"Content-Type" : "multipart/form-data",
}
));
print(response);
print("d");
}catch(e){
}
}
}
这就是我厌烦的 Post 男人:
最后这是我的服务器代码:
@PostMapping(value = "/test")
@ApiOperation(value = "add an event data via the body ")
@ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = ResponseModel.class)})
public ResponseEntity<?> post(@RequestPart("image") MultipartFile image) {
ResponseModel responseModel;
System.out.println(image.getName());
int responseNumber = 0;
String res = response(responseNumber);
if (responseNumber != 0) {
responseModel = new ResponseModel(false, responseNumber, res);
} else {
responseModel = new ResponseModel(true, responseNumber, res);
}
return new ResponseEntity<>( responseModel, HttpStatus.OK);
}
原来你需要实现 web 有点不同,见下文:
Future<String> makeRequest() async {
var url = Uri.parse(
"http://localhost:8080/event/");
var request = new http.MultipartRequest("POST", url);
EventResource eventResource = new EventResource();
//Created and added values to eventResource
var body = jsonEncode(eventResource);
request.files.add(await http.MultipartFile.fromBytes('image', _selectedFile,
contentType: new MediaType('application', 'octet-stream'),
filename: name));
request.files.add(await http.MultipartFile.fromString('body', body,
contentType: new MediaType('application', 'json'),
));
request.headers['Content-Type'] = "application/json";
request.headers['Authorization'] = "SOME_JWT";
request.send().then((response) {
print(response.statusCode);
});