'How to catch SocketException using the http library?

This problem has already been pointed out by others (like here). Althought I may have understood the cause, I still haven't found a solution when using the higher-level http library. For example:

import 'package:http/http.dart';

// yes, pwd is String, it's just a test...
Future<Response> login(String user, String pwd) {
  final authHeader = encodeBasicCredentials(user, pwd);
  return get(
    'http://192.168.0.100:8080/login',
    headers: <String, String>{
    HttpHeaders.AUTHORIZATION: authHeader,
    },
  ));
}

I can't find a way to catch a SocketException that is thrown, for example, if the host can't be reached (in my case, wrong host ip). I have tried wrapping the await in try/catch, or using Future.catchError.

This is a stacktrace of the exception:

[ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 4036): SocketException: OS Error: Connection refused, errno = 111, address = 192.168.0.100, port = 35588
E/flutter ( 4036): #0      IOClient.send (package:http/src/io_client.dart:30:23)
E/flutter ( 4036): <asynchronous suspension>
E/flutter ( 4036): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:171:38)
E/flutter ( 4036): <asynchronous suspension>
E/flutter ( 4036): #2      BaseClient.get (package:http/src/base_client.dart:34:5)
E/flutter ( 4036): #3      get.<anonymous closure> (package:http/http.dart:47:34)
E/flutter ( 4036): #4      _withClient (package:http/http.dart:167:20)
E/flutter ( 4036): <asynchronous suspension>
E/flutter ( 4036): #5      get (package:http/http.dart:47:3)


Solution 1:[1]

You can change login to be async so that you can await the response. That allows you to catch the exception (and, for example, return null instead of the Response).

Future<Response> login(String user, String pwd) async {
  final String authHeader = encodeBasicCredentials(user, pwd);
  try {
    return await get(
        'http://192.168.0.100:8080/login',
        headers: {
          HttpHeaders.AUTHORIZATION: authHeader,
        },
      );
  } catch (e) {
    print(e);
    return null;
  }
}

Solution 2:[2]

You can check the type of the exception and treat it accordingly something like:

Future<Response> login(String user, String pwd) async {
  final String authHeader = encodeBasicCredentials(user, pwd);
  try {
    return await get(
        'http://192.168.0.100:8080/login',
        headers: {
          HttpHeaders.AUTHORIZATION: authHeader,
        },
      );
  } catch (e) {
    if(e is SocketException){
       //treat SocketException
       print("Socket exception: ${e.toString()}");
    }
    else if(e is TimeoutException){
       //treat TimeoutException
       print("Timeout exception: ${e.toString()}");
    }
    else print("Unhandled exception: ${e.toString()}");
  }
}

Probly better off making an error handler lib, so you can just call a function like handleException(e); on the catch block.

Solution 3:[3]

SocketException on http

 try {

    } on SocketException {

    }

Solution 4:[4]

One simple way to catch the error is to call a method on the get method by using the catch error argument like so. This method of the get method can catch others types of errors, not only the socket exception. Look at the code below for more

import 'package:http/http.dart';

Future<Response> login(String user, String pwd) {
final authHeader = encodeBasicCredentials(user, pwd);
return get(
 'http://192.168.0.100:8080/login',
      headers: <String, String>{
    HttpHeaders.AUTHORIZATION: authHeader,
    },
     ).catchError(error){
    //you can now do your error handling in this block
       });
     }
 }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Richard Heap
Solution 2 Fabio Dias
Solution 3 BIS Tech
Solution 4 Ransford Owusu