Image not uploading in DIO 4 and above - flutter

Greeting everyone, my image is not uploading to my server when i update to DIO 4.0.0 and above. The same code works for DIO version below 4.0.0 . Below is the upload code. Kindly help me out. Thanks
Future<dynamic> upload(String url, BuildContext context,
{List<File> files,
Map body,
FileCount count = FileCount.MULTIPLE,
authorize = true}) async {
BaseOptions options = await getOptions(validate: authorize);
dynamic response, serverResponse;
List<MultipartFile> uploadFiles = [];
FormData requestData;
try {
Dio dio = new Dio(options)..interceptors.add(Logging());
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
SecurityContext sc = new SecurityContext();
HttpClient httpClient = new HttpClient(context: sc);
//allow all cert
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return httpClient;
};
// add files to uploadFiles array
if (files.length > 0) {
for (var index = 0; index < files.length; index++) {
MultipartFile file = MultipartFile.fromFileSync(files[index].path,
filename: basename(files[index].path),contentType:MediaType.parse('image/jpg'));
uploadFiles.add(file);
}
print("file the request: $uploadFiles");
requestData = FormData.fromMap({"file": uploadFiles});
} else {
requestData = FormData();
}
body.forEach((key, value) {
MapEntry<String, String> data = new MapEntry(key, '$value');
requestData.fields.add(data);
});
print("sending the request: ${uploadFiles.asMap().values}");
serverResponse = await dio.post(
url,
data: requestData,
options: new Options(contentType: 'multipart/form-data'),
onSendProgress: (int sent, int total) {
print('$sent $total');
},
);
print("Server Replied: $serverResponse}");
print(serverResponse.data);
//check for connection errors
if (serverResponse.statusCode < 200 || serverResponse.statusCode > 400) {
return _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("error_executing_request")}"}');
}
response = _decoder.convert(serverResponse.data);
print("Response: $response");
} on DioError catch (e) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx and is also not 304.
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
// print(e.response.request);
response = _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("server_error")}"}');
} else {
// Something happened in setting up or sending the request that triggered an Error
print(e.message);
response =
_decoder.convert('{"success":false,"message":"' + e.message + '"}');
}
} catch (error) {
return _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("error_executing_request")}"}');
}
return response;
}

Related

Flutter: How to send multiple images using for loop

I am using http package to perform multipart request.I am trying to upload multiple images using for loop but I am not getting any idea how to do it following is my postman response in the below image you can see 2 fields one is attribute and another one is image here I want to loop only adhar and pan inside attributes after sending "mobileno":"4567654","role":"p","userstatus":"D", to database
following is my multipart request code
Future<void> insertCategory(String category, BuildContext context) async {
var flutterFunctions =
Provider.of<FlutterFunctions>(context, listen: false);
var data = {"mobileno":"4567654","role":"p","userstatus":"D","adhar":"adhar","pan":"pan"};
var url = PurohitApi().baseUrl + PurohitApi().insertcategory;
Map<String, String> obj = {"attributes": json.encode(data).toString()};
try {
loading();
final client = RetryClient(
http.Client(),
retries: 4,
when: (reponse) {
return reponse.statusCode == 401 ? true : false;
},
onRetry: (request, response, retryCount) async {
if (retryCount == 0 && response?.statusCode == 401) {
var accesstoken = await Provider.of<Auth>(context, listen: false)
.restoreAccessToken();
request.headers['Authorization'] = accesstoken;
print(accesstoken);
}
},
);
var response = await http.MultipartRequest('Post', Uri.parse(url))
..files.add(await http.MultipartFile.fromPath(
"imagefile", flutterFunctions.imageFile!.path,
contentType: MediaType("image", "jpg")))
..headers['Authorization'] = token!
..fields.addAll(obj);
final send = await client.send(response);
final res = await http.Response.fromStream(send);
var messages = json.decode(res.body);
loading();
print(messages);
} catch (e) {
print(e);
}
}
Future<Object> addUserImages(List<XFile> files, String userID, String token) async {
try {
var url = Uri.parse(API_BASE_URL + addUserImagesUrl);
var request = http.MultipartRequest("POST", url);
request.headers['Authorization'] = "Bearer ${StaticServices.userBaseModel!.token!.token}";
for (var i = 0; i < files.length; i++) {
String fileName = DateTime.now().microsecondsSinceEpoch.toString().characters.takeLast(7).toString();
var pic = http.MultipartFile.fromBytes("files", await File(files[i].path).readAsBytes(), filename: '${userID}_${i}_$fileName', contentType: MediaType("image", files[i].mimeType ?? "png"));
//add multipart to request
request.files.add(pic);
}
var response = await request.send();
var responseData = await response.stream.toBytes();
var responseString = String.fromCharCodes(responseData);
if (response.statusCode == 200) {
return Success(response: Images.fromJson(jsonDecode(responseString)));
}
return Failure(
errorMessage: responseString,
);
} on HttpException {
return Failure(errorMessage: "No Internet Connection");
} on FormatException {
return Failure(errorMessage: "Invalid Format");
} on SocketException {
return Failure(errorMessage: "No Internet Connection");
} catch (e) {
return Failure(errorMessage: "Invalid Error");
}
}

cannot able to send files with extact format in flutter

I'm currently working in a flutter, I'm trying to send a file to the backend server. But I can send a file but the extension is showing as BIN and the file is not supported.
pick() async {
var img = await ImagePicker().getImage(source: ImageSource.gallery);
image = img;
}
send() async {
// if (imageFile == null) {
// return Get.snackbar("alert", 'Please select image');
// }
try {
String? message = messageController.text;
final url = Uri.parse('http://localhost:8000/integration-test');
//Map<String, String> headers = {'Authorization': 'Bearer $token'};
Uint8List data = await this.image.readAsBytes();
List<int> list = data.cast();
var request = http.MultipartRequest('POST', url)
//..headers.addAll(headers)
..fields['sender'] = "venkat"
..fields['numbers'] = numbers
..fields['message'] = message;
if (image != null) {
request.files.add(http.MultipartFile.fromBytes('file', list,
filename: 'example.jpeg'));
}
var response = await request.send();
//var decoded = await response.stream.bytesToString().then(json.decode);
if (response.statusCode == 200) {
Get.snackbar("alert", 'SUCESS');
} else {
Get.snackbar("alert", 'FAILED');
}
} catch (e) {
Get.snackbar('alert', 'Image failed: $e');
}
}
and help to set the file name dynamically.
when i done it with ajax and jquery it works file i need the exact result like this
let formData = new FormData();
let file = $('#1file')[0].files[0];
const sender=c;
const message = $('.i-message').val();
const datepick=$("#i-datetimepicker").val();
formData.append('sender',c);
formData.append('numbers',JSON.stringify(irecepient));
formData.append('message',message);
if(file){
formData.append('file',file);
}
if(datepick){
formData.append('date',datepick);
}
$.ajax({
type: "POST",
url: "http://localhost:8000/integration-test",
//enctype: 'multipart/form-data',
contentType:false,
processData:false,
data: formData,
success: function (data) {
if(data !=0){
$('.logs').append($('<li>').text("task processing"));
}else{
$('.logs').append($('<li>').text("task failed"));
}
}
});
});
this works good and i expect the above flutter code to do this

What the equivalent code in flutter dio compare to android retrofit #body?

Now I try to transform my Andorid project to flutter. but I stucked on an api call.
here is my android code in Kotlin:
/**
* sendSms
*
* #return
*/
#Headers("Content-Type: application/json;charset=UTF-8")
#POST("uaa/sms/send/code")
fun sendSms(#Body params: Map<String, String?>): Observable<ApiResult<String>>
Now I want to implement this api call in flutter use dio, but I still got wrong, my flutter code
is :
class Req {
static Req _instance;
static const int connectTimeOut = 5 * 1000;
static const int receiveTimeOut = 7 * 1000;
static Req getInstance() {
if (_instance == null) {
_instance = Req._internal();
}
return _instance;
}
Dio _client;
Req._internal() {
if (_client == null) {
BaseOptions options = new BaseOptions();
options.connectTimeout = connectTimeOut;
options.receiveTimeout = receiveTimeOut;
_client = new Dio(BaseOptions(
baseUrl: 'https://gw.ec.iunicorn.com/',
));
// 添加缓存插件
_client.interceptors.add(Global.netCache);
//添加token
_client.interceptors.add(Global.tokenInterceptor);
_client.interceptors.add(Global.logInterceptor);
// dio.options.headers[HttpHeaders.authorizationHeader] = Global.profile.token;
_client.options.headers['source'] = 'ANDROID';
if (!Global.isRelease) {
(_client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
// client.findProxy = (uri) {
// return "PROXY 10.1.10.250:8888";
// };
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
}
}
}
//post请求
void post(
String url,
OnData callBack, {
Map<String, String> params,
Options options,
FormData formData,
OnError errorCallBack,
CancelToken token,
}) async {
this._request(
url,
callBack,
method: RequestType.POST,
options: options,
formData: formData,
params: params,
errorCallBack: errorCallBack,
token: token,
);
}
void _request(
String url,
OnData callBack, {
RequestType method,
Map<String, String> params,
Options options,
FormData formData,
OnError errorCallBack,
ProgressCallback progressCallBack,
CancelToken token,
}) async {
final id = _id++;
int statusCode;
try {
Response response;
if (method == RequestType.GET) {
if (mapNoEmpty(params)) {
response = await _client.get(url,
queryParameters: params, cancelToken: token);
} else {
response = await _client.get(url, cancelToken: token);
}
} else {
if (mapNoEmpty(params) || formData != null) {
response = await _client.post(
url,
data: formData ?? params,
onSendProgress: progressCallBack,
cancelToken: token,
);
} else {
response = await _client.post(url, cancelToken: token);
}
}
statusCode = response.statusCode;
if (response != null) {
if (response.data is List) {
Map data = response.data[0];
callBack(data);
} else {
Map data = response.data;
callBack(data);
}
print('HTTP_REQUEST_URL::[$id]::$url');
print('HTTP_REQUEST_BODY::[$id]::${params ?? ' no'}');
print('HTTP_RESPONSE_BODY::[$id]::${response.data}');
}
if (statusCode < 0) {
_handError(errorCallBack, statusCode);
return;
}
} catch (e) {
_handError(errorCallBack, statusCode);
}
}
///处理异常
static void _handError(OnError errorCallback, int statusCode) {
String errorMsg = 'Network request error';
if (errorCallback != null) {
errorCallback(errorMsg, statusCode);
}
print("HTTP_RESPONSE_ERROR::$errorMsg code:$statusCode");
}
}
void sendSms(BuildContext context, Callback callback) async {
Req.getInstance().post(
ApiPath.SEND_SMS,
(t) {
SmsResponse r = SmsResponse.fromJson(t);
print(r);
if (callback != null) {
callback();
}
},
formData: FormData.fromMap({
'phoneNumber':'182********'
}),
options: RequestOptions(
headers: {
HttpHeaders.contentTypeHeader: 'application/json;charset=UTF-8',
}),
errorCallBack: (msg, code) {
Fluttertoast.showToast(
msg: AppLocalizations.of(context).send_sms_fail,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.orangeAccent,
timeInSecForIosWeb: 1);
});
}
Now I want to know is the data in dio is equivalent to the #Body in java retrofit, if not, how can I do?
Doing this in plain Dio leads to a lot of boilerplate. There is also an equivalent retrofit package for Flutter inspired by the same package for Android. https://pub.dev/packages?q=retrofit
From there it's almost the same, you just add () after #Body. Here is an example
#POST('/auth/change-password')
Future<bool> changePassword({
#required #Body() Map<String, dynamic> params,
#required #Header('auth-token') String token,
});

CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate in MultipartFile

HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:354))
getting HandshakeException while upload file and fields
const TestMode = true;
addAssets(Map formFields, List files) async {
Map resp = {
'Status' : false,
'Msg' : "Unable to add asset"
};
try {
Uri url = Uri.parse("$BaseUrl$AddAssetUrl");
http.MultipartRequest multi = http.MultipartRequest("POST", url);
formFields.forEach((key, val) {
multi.fields[key] = val;
});
for (var val in files) {
var myFile = await http.MultipartFile.fromPath('MediaFiles[]', val);
multi.files.add(
myFile,
);
}
http.StreamedResponse streamedResponse = await multi.send().then((response) async {
return response;
});
String body = await streamedResponse.stream.bytesToString();
if(streamedResponse.statusCode == 200 && isJSON(body)){
Map data = json.decode(body);
resp['Status'] = data['Status'];
resp['Msg'] = data['Msg'];
}
debugPrint(body);
} catch (e) {
if(TestMode) print(e.toString());
}
return resp;
}
Upload file using MultipartFile
TestMode is constant
http is alias of package:http/http.
Reference: Github
Just send your request via IOClient
example:
addAssets(Map formFields, List files) async {
Map resp = {
'Status' : false,
'Msg' : "Unable to add asset"
};
try {
Uri url = Uri.parse("$BaseUrl$AddAssetUrl");
http.MultipartRequest multi = http.MultipartRequest("POST", url);
formFields.forEach((key, val) {
multi.fields[key] = val;
});
for (var val in files) {
var myFile = await http.MultipartFile.fromPath('MediaFiles[]', val);
multi.files.add(
myFile,
);
}
HttpClient httpClient = HttpClient();
httpClient .badCertificateCallback = (X509Certificate cert,String host,int port) {
return getBaseUrl() == host;
};
http.StreamedResponse streamedResponse = await IOClient(
httpClient
).send(multi);
String body = await streamedResponse.stream.bytesToString();
if(streamedResponse.statusCode == 200 && isJSON(body)){
Map data = json.decode(body);
resp['Status'] = data['Status'];
resp['Msg'] = data['Msg'];
}
debugPrint(body);
} catch (e) {
if(TestMode) print(e.toString());
}
return resp;
}
String getBaseUrl(){
String url = 'https://hostname.com/api_dir/'; // Your api url
url = url.substring(url.indexOf('://')+3);
return url.substring(0,url.indexOf('/'));
}

Invalid request payload input on flutter post request

I am trying to uploading multiple files from my flutter mobile app. Here is my screenshot of the postman. This works fine on postMan. But I am getting 400 errors on the flutter mobile app. I can't find out where is the problem?
Now here is the code of my flutter mobile app upload.
if(images.length>0){
for (int i = 0; i < images.length; i++) {
var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
String fileName = path.split('/').last;
var file = await MultipartFile.fromFile(path, filename:fileName);
multipart.add(file);
}
FormData imageFormData = FormData.fromMap(
{
"feedId": value.id,
"images": multipart,
"userInformationsId": value.userInformationId
});
print(multipart.length);
uploadFeedPicture(imageFormData);
}
Future<String> uploadFeedPicture(FormData _imageformData) async{
String at = await _apiProvider.getAccessToken();
Dio dio = new Dio();
// dio.options.headers['accept'] = 'application/json';
// dio.options.headers["content-Type"] = "multipart/form-data";
dio.options.headers["Authorization"] = "Bearer ${at}";
dio.options.baseUrl = getBaseUrl();
var _baseUrl = getBaseUrl();
await dio.post('/api/feed/upload', data: _imageformData, options: Options(
followRedirects: false,
validateStatus: (status) { return status < 500; }
), onSendProgress: (int sent, int total) {
print("$sent $total");
},).then((value) {
print(value.data);
print(value.headers);
}
).catchError((error) => print(error) );
}
And I am getting this response.
{statusCode: 400, error: Bad Request, message: Invalid request payload input}
Please Help me out where is the problem? I try with change content-type but not working.
After trying so many different ways I found the solution. Here it is.
if(value.id != null){
String at = await _apiProvider.getAccessToken();
Map<String, String> headers = { "Authorization": "Bearer ${at}"};
var uri = Uri.parse('$baseUrl/api/feed/upload');
var request = http.MultipartRequest('POST', uri);
request.headers.addAll(headers);
if(images.length>0){
for (int i = 0; i < images.length; i++) {
var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
// String fileName = path.split('/').last;
var file = await MultipartFile.fromPath("images",path);
request.files.add(file);
}
request..fields['feedId'] = value.id;
request..fields['userInformationsId'] = value.userInformationId;
var response = await request.send();
if (response.statusCode == 200) {
Navigator.pop(context);
showSuccessToast("Posted succesfull");
counter.update(0);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}else{
showErrorToast("Upload image failed");
}
}
}