I want to catch an exception if the app fails to connect to the server (If the server is turned off for example) but not sure how and didn't succeed so far.
My code:
static Future<String> communicate(String img, String size) async
{
String request = size.padLeft(10, '0') + img;
Socket _socket;
await Socket.connect(ip, 9933).then((Socket sock)
{
_socket = sock;
}).then((_)
{
//Send to server
_socket.add(ascii.encode(request));
return _socket.first;
}).then((data)
{
//Get answer from server
response = ascii.decode(base64.decode(new String.fromCharCodes(data).trim()));
});
return response;
}
Function call:
var ans = await communicate(bs64Image, size);
In general, you handle errors like this with async/await:
try {
// code that might throw an exception
}
on Exception1 {
// exception handling code
}
catch Exception2 {
// exception handling
}
finally {
// code that should always execute; irrespective of the exception
}
In your case, you should try something like:
try {
var ans = await communicate(bs64Image, size);
}
catch (e){
print(e.error);
}
finally {
print("finished with exceptions");
}
Try using SocketException if request fails exception will be thrown
import 'dart:io';
try {
response = await get(url);
} on SocketException catch (e) {
return e;
}
Related
a have a question, I need to apply limit in the messages array but I do khow can I do it.
static Stream<Room?> listenChatRoom(int roomId) {
try {
var builder = objectBox.store
.box<RoomObjectBoxModel>()
.query(RoomObjectBoxModel_.id.equals(roomId));
builder.linkMany(RoomObjectBoxModel_.messages, RoomObjectBoxModel_.roomType.equals("chat"));
return builder.watch(triggerImmediately: true).transform(
StreamTransformer.fromHandlers(handleData: (query, sink) {
sink.add(query.findFirst()?.toDomain());
}),
);
} catch (ex) {
rethrow;
}
}
I define axios like below
$axios.onResponse((response) => {
if (response.data.status == 500}
return Promise.reject(response)
}
})
$axios.onError((err) => {
console.log(err)
})
and in fetch i call
async fetch () {
await this.$axios.$get('myapi')
}
but i get error like
RangeError
Maximum call stack size exceeded
I try to reject a success response to error but it not working in ssr. How to fix that thank.
Generally, using try-catch statements are preferred over event handlers (where appropriate).
Try something like this:
async fetch() {
try {
const response = await this.$axios.$get('myapi');
if (response.data.status == 500) {
throw new Error("Some error message");
} else {
// Success action here
}
} catch(err) {
console.log(err);
}
}
Is there any particular reason you're returning a rejected Promise when you get a 500 error? Is there any reason not to throw a generalized error message instead?
I'm using the following code to successfully poll mysite for JSON data and return that data. If the request fails, then it successfully returns an error message as well return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);.
What I'd like to happen is have the app retry the request 3 times before it returns the error message.
Basically have the future call itself for some number of iterations.
I did try to create an external function that would get called from the outer catch which then would in turn call the getJSONfromTheSite function a second and then a third time, but the problem was that you would have a non-null return from the Future so the app wouldn't accept that approach
Is there another way of doing this?
Future<Result> getJSONfromTheSite(String call) async {
debugPrint('Network Attempt by getJSONfromTheSite');
try {
final response = await http.get(Uri.parse('http://www.thesite.com/'));
if (response.statusCode == 200) {
return Result<AppData>.success(AppData.fromRawJson(response.body));
} else {
//return Result.error("Error","Status code not 200", 1);
return Result.error(title:"Error",msg:"Status code not 200", errorcode:1);
}
} catch (error) {
return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);
}
}
The following extension method will take a factory for futures, create them and try them until the retry limit is reached:
extension Retry<T> on Future<T> Function() {
Future<T> withRetries(int count) async {
while(true) {
try {
final future = this();
return await future;
}
catch (e) {
if(count > 0) {
count--;
}
else {
rethrow;
}
}
}
}
}
Assuming you have a rather plain dart method:
Future<AppData> getJSONfromTheSite(String call) async {
final response = await http.get(Uri.parse('http://www.thesite.com/'));
if (response.statusCode == 200) {
return AppData.fromRawJson(response.body);
} else {
throw Exception('Error');
}
}
You can now call it like this:
try {
final result = (() => getJSONfromTheSite('call data')).withRetries(3);
// succeeded at some point, "result" being the successful result
}
catch (e) {
// failed 3 times, the last error is in "e"
}
If you don't have a plain method that either succeeds or throws an exception, you will have to adjust the retry method to know when something is an error. Maybe use one of the more functional packages that have an Either type so you can figure out whether a return value is an error.
Inside catch() you can count how many times have you retried, if counter is less than three you return the same getJSONfromTheSite() function, but with the summed counter. And if the connection keeps failing on try{} and the counter is greater than three it will then returns the error.
Future<Result> getJSONfromTheSite(String call, {counter = 0}) async {
debugPrint('Network Attempt by getJSONfromTheSite');
try {
String? body = await tryGet();
if (body != null) {
return Result<AppData>.success(AppData.fromRawJson(response.body));
} else {
//return Result.error("Error","Status code not 200", 1);
return Result.error(title:"Error",msg:"Status code not 200", errorcode:1);
}
} catch (error) {
if(counter < 3) {
counter += 1;
return getJSONfromTheSite(call, counter: counter);
} else {
return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);
}
}
}
this code sample
import 'package:flutter_test/flutter_test.dart';
void main() {
const one = 1;
String oneAsString() => one as String;
test('Make sure it fails', () {
var s;
var _e;
try {
s = oneAsString();
} on Error catch (e) {
_e = e;
}
expect(s == null, true, reason: 'should fail');
expect(_e == null, false, reason: 'error or exception should be returned');
});
test('Catchin Error', () {
var _e;
try {
oneAsString();
} on Error catch (e) {
_e = e;
}
expect(_e is Error, true, reason: 'should be an error');
});
test('Catchin Exception', () {
var _e;
try {
oneAsString();
} on Exception catch (e) {
_e = e;
}
expect(_e is Exception, true, reason: 'should be an exception');
});
test('Why not BOTH', () {
var _e;
try {
oneAsString();
} on Error catch (e) {
_e = e;
} on Exception catch (e) {
_e = e;
}
expect(_e is Error, true, reason: 'should be an error');
expect(_e is Exception, false, reason: 'should NOT be an exception');
});
}
outputs this result
00:02 +2 -1: Catchin Exception [E]
type 'int' is not a subtype of type 'String' in type cast
test/widget_test.dart 5:31 main.oneAsString
test/widget_test.dart 31:18 main.<fn>
00:02 +3 -1: Some tests failed.
the safest approach seems to be Why not BOTH, but following effective dart
(enforcing it with the package effective_dart)
the analysis complains about avoid_catching_errors
DON'T explicitly catch Error or types that implement it.
Errors differ from Exceptions in that Errors can be analyzed and
prevented prior to runtime. It should almost never be necessary to
catch an error at runtime.
BAD:
try { somethingRisky(); } on Error catch(e) { doSomething(e); }
GOOD:
try { somethingRisky(); } on Exception catch(e) { doSomething(e);
}
and if I simple do
try {} catch (e) {}
the analyzer complains about avoid_catches_without_on_clauses
AVOID catches without on clauses.
Using catch clauses without on clauses make your code prone to
encountering unexpected errors that won't be thrown (and thus will go
unnoticed).
BAD:
try { somethingRisky() } catch(e) { doSomething(e); } GOOD:
try { somethingRisky() } on Exception catch(e) { doSomething(e); }
what is the correct approach to catch BOTH Error and Exception?
re-posting the answer from #Miyoyo on r/FlutterDev discord
Optimally? You do not catch error
Just, at all
Remember effective dart is Guidelines
Using them as gospel will make some things impossible
Catching error is deliberately made to be "not according to guidelines"
because you're not supposed to do that
for my use case I'll just add
// ignore_for_file: avoid_catching_errors
Let's say I have the following synchronous code that requires original arguments when handling errors:
var input = createInput(123);
try {
doWork(input);
} catch (err) {
handleError(input, err); // error handling requires input
}
What is the best way to pass the original arguments to the error hander?
Rx.Observable.just(123).map(createInput).map(doWork).subscribe(
function(result) {
// success
},
function(err) {
// how can I get the argument of doWork (the result of createInput) here?
}
);
Just add it as a property of the Error object before you throw it or in wrapper code like below.
...map(function (value) {
try {
return createInput(value);
}
catch (e) {
e.lastValue = value;
throw e;
}
}).subscribe(..., function (e) {
e.lastValue...