Guia Definitivo para Tratamento de Erros com Dio: Criando Experiências de Aplicativo Flutter Amigáveis ao Usuário
Dio é um poderoso cliente HTTP para Dart e Flutter, que suporta configurações globais, interceptadores, FormData, abortar e cancelar uma requisição, upload e download de arquivos, timeout de requisições, adaptadores personalizados, entre outros recursos. No desenvolvimento de aplicativos móveis, o tratamento de erros de rede é um ponto chave para melhorar a experiência do usuário. Este artigo irá detalhar como utilizar o Dio para um tratamento abrangente de erros, ajudando desenvolvedores a construir aplicativos Flutter mais robustos e amigáveis.
Conhecendo o Sistema de Exceções do Dio
O framework Dio define um mecanismo unificado de tratamento de erros. Todos os erros relaciondaos à rede são encapsulados como objetos DioException. Ao capturar essa exceção, podemos obter informações cruciais como o tipo do erro, mensagem, dados da resposta, etc., permitindo fornecer feedback preciso ao usuário.

Detalhamento dos Tipos de Erro DioExceptionType
O Dio define vários tipos de erro, cada um correspondendo a diferentes cenários de problemas de rede:
- connectionTimeout: Erro de timeout na conexão, disparado quando o cliente não consegue estabelecer conexão com o servidor dentro do tempo especificado.
- sendTimeout: Timeout no envio, quando o envio dos dados da requisição excede o tempo limite.
- receiveTimeout: Timeout na recepção, quando o servidor não retorna uma resposta dentro do tempo especificado.
- badResponse: Resposta com erro, quando o servidor retorna um código de status 4xx ou 5xx.
- cancel: Requisição cancelada, geralmente acionada por um
CancelToken. - connectionError: Erro de conexão, como ausência de rede ou falha na resolução de DNS.
- badCertificate: Erro de certificado, falha na validação do certificado SSL.
- unknown: Erro desconhecido, outros tipos não classificados.
Captura e Tratamento Básico de Erros
Uso Básico do try-catch
A forma mais básica de tratamento é usar o bloco try-catch para capturar DioException:
try {
var resultado = await dio.get('/api/dados');
// Processar resposta bem-sucedida
} on DioException catch (erro) {
// Tratar erro do Dio
tratarErroDio(erro);
} catch (erro) {
// Tratar outros tipos de erro
print('Erro inesperado: $erro');
}
Essa abordagem captura exceções específicas do Dio sem interferir no tratamento de outros tipos.
Extração de Informações do Erro
Podemos extrair várias informações úteis de um DioException:
void tratarErroDio(DioException erro) {
switch (erro.type) {
case DioExceptionType.connectionTimeout:
exibirErro('Tempo limite de conexão esgotado. Verifique sua rede.');
break;
case DioExceptionType.receiveTimeout:
exibirErro('Tempo limite de resposta do servidor esgotado.');
break;
case DioExceptionType.badResponse:
exibirErro('Erro no servidor: ${erro.response?.statusCode}');
// Pode obter detalhes do erro da resposta
print('Dados da resposta com erro: ${erro.response?.data}');
break;
// Outros tipos de erro...
}
}
Estratégias Avançadas de Tratamento de Erros
Uso de Interceptadores para Tratamento Unificado
Os interceptadores do Dio permitem tratar erros de forma global, evitadno repetir código em cada requisição.
class InterceptadorDeErros extends Interceptor {
@override
void onError(DioException erro, ErrorInterceptorHandler manipulador) {
// Lógica unificada de tratamento
switch (erro.type) {
case DioExceptionType.connectionError:
// Sem rede
exibirDialogoSemRede();
break;
case DioExceptionType.badResponse:
if (erro.response?.statusCode == 401) {
// Não autorizado, lidar com token expirado etc.
lidarComNaoAutorizado();
}
break;
}
super.onError(erro, manipulador);
}
}
// Adicionar interceptador
dio.interceptors.add(InterceptadorDeErros());
Tratamento de Cancelamento de Requisição
Dio oferece o mecanismo CancelToken para cancelar requisições a qualquer momento, útil quando o usuário sai da página ou inicia uma nova requisição:
CancelToken tokenCancelamento = CancelToken();
// Iniciar requisição
dio.get('/api/dados', cancelToken: tokenCancelamento)
.catchError((erro) {
if (DioExceptionType.cancel == erro.type) {
print('Requisição cancelada');
}
});
// Cancelar requisição
tokenCancelamento.cancel('Requisição cancelada pelo usuário');
Recomendações para Melhorai da Experiência do Usuário
Design de Mensagens de Erro
Boas mensagens de erro devem:
- Ser claras e concisas, evitando jargões técnicos.
- Oferecer soluções ou sugestões de próximos passos.
- Ser visualmente destacadas, mas sem atrapalhar a interação do usuário.
Gerenciamento de Estado de Carregamento
Combine tratamento de erros com um fluxo completo de carregamento, erro e repetição:
Future<void> buscarDados() async {
setState(() => _carregando = true);
try {
var resposta = await dio.get('/api/dados');
setState(() {
_dados = resposta.data;
_erro = null;
});
} on DioException catch (erro) {
setState(() {
_erro = erro;
_dados = null;
});
} finally {
setState(() => _carregando = false);
}
}
Implementação de Mecanismo de Repetição
Para problemas temporários de rede, repetir a requisição de forma inteligente pode melhorar a experiência:
Future<Response> requisicaoComRepeticao(Future<Response> Function() requisicao, {int maxTentativas = 3}) async {
int tentativas = 0;
while (true) {
try {
return await requisicao();
} on DioException catch (erro) {
tentativas++;
if (tentativas >= maxTentativas || !_podeRepetir(erro)) {
rethrow;
}
// Estratégia de backoff exponencial
await Future.delayed(Duration(milliseconds: 300 * (1 << (tentativas - 1))));
}
}
}
bool _podeRepetir(DioException erro) {
return erro.type == DioExceptionType.connectionError ||
erro.type == DioExceptionType.connectionTimeout ||
(erro.type == DioExceptionType.badResponse && erro.response?.statusCode >= 500);
}
Dicas de Teste e Depuração
Simulação de Cenários de Erro
Dio fornece um mecanismo de adaptadores que facilita a simulação de vários cenários de erro para testes:
// Usar MockAdapter para simular resposta de erro
dio.httpClientAdapter = MockAdapter()
..onGet('/api/dados', (requisicao) {
return requisicao.reply(500, {'erro': 'Erro interno do servidor'});
});
Registro de Logs de Erro
Registre logs de erro em ambientes de desenvolvimento e produção para auxiliar no diagnóstico:
class InterceptadorDeLog extends Interceptor {
@override
void onError(DioException erro, ErrorInterceptorHandler manipulador) {
// Registrar log de erro
print('''
[Erro Dio]
Tipo: ${erro.type}
Mensagem: ${erro.message}
StackTrace: ${erro.stackTrace}
Resposta: ${erro.response}
''');
super.onError(erro, manipulador);
}
}