Flutter Dio interceptor: DioError [DioErrorType.DEFAULT]: Bad state: Can‘t finalize a finalized MultipartFile - flutter

Hi i'm trying refreshtoken logic in Dio interceptor. it's working fine for json body params, but its throwing DioError [DioErrorType.DEFAULT]: Bad state: Can‘t finalize a finalized MultipartFile when i tried uploading images.
onError: (DioError error) async {
// Do something with response error
if (error.response?.statusCode == 401) {
// _dio.interceptors.requestLock.lock();
Response response;
RequestOptions options = error.response.request;
response = await _dio
.post('/user/refresh', data: {"refreshToken": _refreshToken});
if (response.statusCode == 200) {
final userData = json.encode(
{
'token': response.data["accessToken"],
'tokenType': _tokenType,
'refreshToken': response.data["refreshToken"]
},
);
prefs.setString('userData', userData);
options.data = formData;
}
options.headers["Authorization"] =
"$_tokenType ${response.data['accessToken']}";
return await _dio.request(options.path, options: options);
} else {
throw error;
}

I put together a workaround for this issue which basically consists of rebuilding the FormData before retrying. It feels a bit hacky but it works. I start by passing any info I need for the reconstruction in via the "extra" map in the request options so the interceptor has access to it. Here is some pseudo code:
//original request
dioResponse = await dio.post(
'http://my/api/endpoint',
data: myOriginalFormData,
options: Options(
headers: myHeaders,
extra: {'pathToMyFile': pathToMyFile},
),
);
//and in my interceptor I use it to construct a fresh FormData that has not been finalized
final FormData newFormData = FormData.fromMap({
'file': await MultipartFile.fromFile(
requestOptions.extra['pathToMyFile'],
contentType: MediaType('application/json', 'json')),
});
//retry with the fresh FormData
return dio.request(
requestOptions.path,
data: newFormData,
options: requestOptions,
cancelToken: requestOptions.cancelToken,
onReceiveProgress: requestOptions.onReceiveProgress,
onSendProgress: requestOptions.onSendProgress,
queryParameters: requestOptions.queryParameters,
);
Anyone have thoughts on this approach? Any major downsides?

Related

How to fire interceptor with post request and set configurable dio interceptor work every api app

I want to know dio post request how perform interceptor 'onrequest' in response 'onerror'
Above code in 'onerror' request refresh token not working interceptor also any other way
Future getlist() async{
final dio = Dio();
Final storage=Fluttersecurestorage();
String accesstoken =await storage.read('accesstoken');
final response= await dio.post(
url,
data: loginData,
options: Options(headers: {"authorization": 'Bearer $accesstoken'}),
dio.interceptors.clear();
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (request, handler) {
},
onError: (err, handler) async {
if (err.response?.statusCode == 401) {
//request refresh token}
}
}
));

DioError (DioError [DioErrorType.other]: Bad state: Can't finalize a finalized MultipartFile

I am attempting to upload multiple files using Dio, upon the request being sent I am receiving the error:
DioError (DioError [DioErrorType.other]: Bad state: Can't finalize a finalized MultipartFile.
My request is as follows:
Future<String> sendRequest() async {
_className = classController.text;
_studentName = studentController.text;
_assnNum = assignmentController.text;
if (_className != null && _studentName != null && _assnNum != null) {
var url =
"http://157.245.141.117:8000/uploadfile?collection=$_className&assn_num=$_assnNum&student_name=$_studentName";
var uri = Uri.parse(url);
var formData = FormData();
for (var file in _files) {
print('FilePath: ${file.path}');
formData.files.addAll([
MapEntry("assignment", await MultipartFile.fromFile(file.path)),
]);
var response = await dio.post(
url,
data: formData,
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/x-www-form-urlencoded",
}),
);
print(response.statusCode);
}
}
return '';
}
I am receiving a status on my api of 200, all params are being passed, but the files are not being uploaded. I'm not sure where to begin. I am uploading cpp files and python files, most examples I have found are dealing exclusively with images. I am unsure how to proceed.

how to use flutter dio connect-type multipart?

my code here
Dio dio = new Dio();
String fileName = event.file!.path.split('/').last;
FormData formData = FormData.fromMap({
"file":
await MultipartFile.fromFile(event.file!.path, filename: fileName),
});
try {
var response = await dio.post(
"url",
data: formData,
options: new Options(
contentType: "multipart/form-data",
headers: {
"token": await getToken(),
// "Content-Type": "multipart/form-data"
}),
// headers: {"token": "test:1234"}),
);
}
catch (e){
print(e);
}
my error version 1
error type. DioErrorType.other
error : SocketException : OS Error Connection refused,errorno=61
and
my error version 2
error type. DioErrorType.response
error : Http status error[400]
my requestOptions here
method = "POST"
_defaultContentType = "multipart/form-data"
How can I hand over the file to the server? The problem I think is that the content-type is not suitable, so there seems to be an error.
I have a similar implementation. I also use Dio, though in my code, I have it abstracted away with _api.
Future<Response> uploadLogo({#required File file}) async {
String fileName = file.path.split('/').last;
FormData formData = FormData.fromMap({"file": await MultipartFile.fromFile(file.path, filename:fileName) });
return await _api.post(url: url, data: formData);
}
Note that I don't even set the content type. I suspect that Dio looks at the type of object in the data parameter, and handles the appropriate headers/encoding under the hood.
Also, if you have having the content-type set to something unexpected, I'd recommend checking if you are using any RequestInterceptor's. I was, and had to write an exception, because I was setting it correctectly, by my RequestInterceptor was overriding it, (because all of my other endpoints wanted JSON):
class RequestInterceptor extends InterceptorsWrapper {
#override
void onRequest(RequestOptions options, handler) {
if(!options.headers.containsKey('content-type')) {
options.headers['content-type'] = 'application/json';
}
// ...
super.onRequest(options, handler);
}
}

I am not able to upload images and form data to rest api using DIO package in flutter

I am not able to upload image to rest api in flutter I have checked the api its working fine.
I am not able to convert the file (image) to a uploadable form, can any one help me with that?
I have run flutter doctor -v everything is fine :)
Here is the code I am using to post form data:
Future<void> uploadAccountDetails(AccountDetailsModel details) async {
var url = baseUrl + '/api/uploads/images';
try {
Dio dio = new Dio();
FormData formData = new FormData.fromMap(
{
'city': details.cityName,
'country': details.countryName,
'residence_address': details.address,
'dob': details.dob,
'id_num': details.id,
'passport_num': details.passportNo,
'driving_license_nim': details.drivingLicNo,
'user_id': 162,
'postal_code': details.postalCode,
'id_pic': await MultipartFile.fromFile(details.idPic.path,
filename: basename(details.idPic.path)),
'driving_license_pic':
await MultipartFile.fromFile(details.drivingLicPic.path,
filename: basename(
details.drivingLicPic.path,
)),
'birth_certificate': await MultipartFile.fromFile(
details.drivingLicPic.path,
filename: basename(details.birthCertPic.path),
),
'residence_permit_pic': await MultipartFile.fromFile(
details.resPermitPic.path,
filename: basename(details.resPermitPic.path),
),
'profile_pic': await MultipartFile.fromFile(details.profilePic.path,
filename: basename(details.profilePic.path)),
},
);
print(formData);
Response response = await dio.post(
url,
data: formData,
onSendProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.statusCode);
// print(response);
} catch (e) {
print(e);
throw (e);
}
}
The logs of error are as follows:
I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status error
[500] I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status
error [500]
The status error is:
I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status error
[500]
I searched this error but didnt find any solution, can anyone help me with that?
I used dio for post a file path with some other information in this way:
Dio dio = new Dio();
FormData formData = new FormData();
formData.add(
"apiKey",
"my_api_key",
);
formData.add(
"file",
"image_path",
);
Response response = await dio.post(
"https://localhost",
data: formData,
onSendProgress: (int sent, int total) {
// do something
},
).catchError((onError) {
throw Exception('something');
});

How to set headers for POST with flutter and Dio

this is my code below, i'm stuck please help.
void getProducts() async {
String htoken = Utils.prefs.getString("token");
print(htoken);
try {
var dio = Dio(BaseOptions(headers: {"appusertoken": "$htoken"}));
//dio.options.headers["appusertoken"] = "$htoken";
Response response = await dio.post(
'APIURL',
);
print("data coming");
print(response.data);
} on DioError catch (e) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
}
}
it was throwing an error of data null.
I was able to fix the issues.
Add optional parameter options for dio.post method and define headers with Options class:
void getProducts() async {
String htoken = Utils.prefs.getString("token");
try {
Dio dio = Dio();
Response response = await dio.post("http://URL",
data: {},
options: Options(
headers: {"appusertoken": "$htoken"},
));
print("data coming");
print(response);
} on DioError catch (e) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
}
}
For example :
Dio _dio = new Dio();
_dio.options.contentType = Headers.formUrlEncodedContentType;
_dio.options.headers['Authorization'] = 'bearer $authToken';
or use :
final Map<String, dynamic> header = {'Authorization': 'bearer $authToken'};
enter code here
final responseData = await _dio.get(
Apis.account_profit,
options: RequestOptions(
method: 'GET', headers: header, baseUrl: Apis.apiBaseUrl),
);