#spring #flutter #dart #xmlhttprequest #flutter-web
#spring #flutter #dart #xmlhttprequest #flutter-web
Вопрос:
Привет, я пытаюсь создать очень простое приложение flutter, которое делает фотографию с моего рабочего стола и отправляет ее на мой сервер через HTTP.POST (в виде составного файла). Я использовал dio
, чтобы попробовать это, но по какой-то причине мой сервер продолжает указывать это 'image' is not present
. Я попытался отладить почтовый код, изображение отображается в журналах (base64 и т.д.). Я пробую это в PostMan и добиваюсь успеха, хотя с flutter я получаю 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: $_fileStringn'),
],
),
),
);
}
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.nn'
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 man:
Наконец, это мой серверный код:
@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);
}
Комментарии:
1. Пожалуйста, не публикуйте изображения. Вместо этого вы должны опубликовать код и тело запроса. Пожалуйста, отредактируйте его
2. единственным телом запроса являются данные формы, отображаемые на изображении postman
3. Вы пробовали размещать его как изображение, а не как данные из нескольких частей?
4. @JacksonLee что-то вроде json или что-то в этом роде?
5. @JacksonLee я пытаюсь создать сообщение без MultipartFile, вместо этого я использовал строку, и у меня все та же проблема
Ответ №1:
ИТАК, оказывается, вам нужно реализовать 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);
});