Dio é um poderoso cliente HTTP para Dart e Flutter, criado pelo engenheiro chinês Wenda Wang. A biblioteca fornece uma API avançada com suporte a interceptadores, FormData, upload de arquivos e cancelamento de requisições. De acordo com pub.dev, 2025, Dio é o cliente HTTP mais popular no ecossistema Flutter com mais de 8 mil estrelas no GitHub.
Principais pontos
Dio é uma poderosa biblioteca cliente HTTP para a linguagem Dart, mais amplamente usada em aplicações Flutter. Dio fornece uma API rica com suporte a interceptadores, configuração global, transformadores, FormData, upload de arquivos e gerenciamento flexível de timeouts, tornando-se a principal escolha para comunicação de rede na comunidade Flutter.
A biblioteca foi criada por Wenda Wang em 2018 como alternativa ao HttpClient nativo do dart:io, que não possuía muitos recursos modernos: configuração unificada para todas as requisições, interceptadores e serialização automática. Em 2025, Dio superou em popularidade o pacote http da equipe Dart, ocupando o primeiro lugar entre os clientes HTTP no ecossistema Flutter de acordo com o pub.dev.
Dio suporta três adaptadores: DartNativeAdapter (padrão no Android, iOS, Desktop), BrowserAdapter (na Web) e IOAdapter. O adaptador é selecionado automaticamente dependendo da plataforma. Dio também fornece uma interface unificada para todas as plataformas Flutter — Android, iOS, Web, macOS, Windows e Linux.
A arquitetura do Dio é construída em uma cadeia de manipuladores. Cada requisição passa por uma sequência de interceptadores que podem modificar a requisição (InterceptorsWrapper.onRequest), a resposta (onResponse) ou tratar um erro (onError). Após os interceptadores, a requisição vai para os transformadores (Transformer), que transformam os dados antes do envio.
Uma instância do Dio é configurada através de um objeto BaseOptions contendo a URL base, cabeçalhos padrão, timeouts, tipo de resposta (JSON, stream, plain), parâmetros de consulta e formato de dados. Essas configurações se aplicam a todas as requisições, mas podem ser substituídas em uma requisição específica. BaseOptions fornece um ponto único de configuração para toda a aplicação, simplificando alterações de endpoint ou adição de cabeçalhos globais.
Cada requisição no Dio retorna Response<T>, onde T é o tipo de dado após o processamento dos transformadores. Por padrão, o Dio converte automaticamente respostas JSON em Map<String, dynamic>. Para respostas tipadas, o Dio é usado junto com pacotes de serialização: json_serializable, freezed ou built_value. A Response contém data, headers, statusCode, requestOptions e dados extras.
A configuração básica é criada através de Dio(BaseOptions). É possível definir um baseUrl para todas as requisições, connectTimeout e receiveTimeout, cabeçalhos content-type e accept, bem como queryParameters. Todos esses parâmetros se aplicam a cada requisição, eliminando duplicação de código e centralizando o gerenciamento das configurações de rede.
Dio suporta dois modos de serialização: JSON por padrão (responseType: ResponseType.json) e streaming (ResponseType.stream). No modo stream, Response.data retorna um ResponseBody que pode ser lido em partes. Isso é conveniente para arquivos grandes onde carregar tudo na memória é indesejável. O modo plain retorna uma string bruta sem análise JSON automática.
Os interceptadores são o mecanismo chave do Dio para interceptar e modificar requisições, respostas e erros. Eles substituem completamente o Interceptor do OkHttp e os plugins do Ktor, mas com uma API específica do Dart e suporte assíncrono via Future. Os interceptadores podem ser adicionados tanto na configuração global do Dio quanto para requisições individuais.
| Método do interceptador | Propósito | Exemplo de uso |
|---|---|---|
| onRequest | Modificar requisição antes de enviar | Adicionar token de autorização |
| onResponse | Tratar resposta bem-sucedida | Converter data em objetos DTO |
| onError | Tratar erro de requisição | Repetição automática em 503 |
O LogInterceptor integrado registra cada requisição: método, URL, cabeçalhos, corpo e tempo de execução. Ele tem dois modos: compacto (uma linha por requisição) e completo (informação completa com corpo). O LogInterceptor é especialmente útil durante o desenvolvimento, mas é recomendado desativá-lo em builds de release através de imports condicionais ou uma flag global.
Interceptadores personalizados são criados através da classe InterceptorsWrapper. É possível sobrescrever um, dois ou os três métodos (onRequest, onResponse, onError). O Dio executa os interceptadores estritamente na ordem em que são adicionados à lista de interceptadores. Se um interceptador não chamar handler.next(), a cadeia é interrompida e a resposta ou erro não chega à aplicação.
Para autenticação no Dio, usa-se um interceptador que adiciona um token Bearer ao cabeçalho Authorization. Se o servidor retornar 401, o interceptador em onError tenta renovar o token através de uma requisição de refresh e repete a requisição original com o novo token. Este padrão é chamado de token refresh interceptor e é implementado através de DioException verificando response?.statusCode == 401.
Dio fornece suporte integrado para lógica de repetição através do pacote dio_smart_retry ou de um RetryInterceptor personalizado. A repetição é importante para aplicações móveis: quando a conexão é perdida por 2-3 segundos, o Dio lança uma DioException com tipo connectionTimeout ou connectionError. O RetryInterceptor captura essa exceção e repete a requisição até 3 vezes com backoff exponencial (1s, 2s, 4s), melhorando a confiabilidade da aplicação em condições de rede instáveis.
Vejamos uma requisição GET básica com Dio. Uma instância é criada com BaseOptions, definindo a URL base e os timeouts. A requisição é executada através do método get(), retornando uma Response com dados no formato Map.
final dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com',
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
headers: {
'Accept': 'application/vnd.github.v3+json',
},
))
final response = await dio.get('/users/octocat')
print(response.data['login'])
Para uma requisição POST com corpo JSON, um objeto Map ou um DTO personalizado é passado. O Dio serializa automaticamente o Map para JSON através de jsonEncode. Para DTOs tipados, usa-se a opção queryParameters, o campo data ou um Transformer personalizado.
final data = {
'name': 'my-project',
'description': 'Created via Dio',
'private': false,
}
final response = await dio.post(
'/user/repos',
data: data,
options: Options(
contentType: ContentType.json.value,
),
)
print(response.data['id'])
Um interceptador personalizado adiciona um token Bearer a cada requisição. O método onRequest é acionado antes do envio, modificando os cabeçalhos. Em uma resposta 401, o interceptador pode renovar o token e repetir a requisição através do método dio.fetch(requestOptions).
class AuthInterceptor extends InterceptorsWrapper {
final String token
AuthInterceptor(this.token)
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) {
options.headers['Authorization'] = 'Bearer $token'
handler.next(options)
}
}
dio.interceptors.add(AuthInterceptor('ghp_abc123'))
Dio simplifica o upload de arquivos através de FormData. Para enviar um arquivo, um MultipartFile é criado a partir de File, Bytes ou AssetBundle. O FormData define automaticamente o cabeçalho multipart/form-data com o limite e codificação corretos. O Dio suporta progresso de upload através de onSendProgress.
Para download de arquivos, usa-se o método download(), que salva o fluxo de dados diretamente em um arquivo. O Dio suporta retomada de downloads interrompidos através do cabeçalho Range, o que é especialmente útil para arquivos grandes. O progresso do download é rastreado através de onReceiveProgress, permitindo exibir uma barra de progresso na interface do usuário.
final formData = FormData.fromMap({
'file': await MultipartFile.fromFile(
'/path/to/photo.jpg',
filename: 'photo.jpg',
),
'description': 'Profile photo',
})
await dio.post(
'/upload',
data: formData,
onSendProgress: (sent, total) {
final progress = sent / total * 100
print('Upload: $progress%')
},
)
// Download de arquivo
await dio.download(
'https://example.com/file.zip',
'/storage/emulated/0/Download/file.zip',
onReceiveProgress: (received, total) {
print('Download: ${received / total * 100}%')
},
)
Tratamento incorreto de erros é o problema mais comum. O Dio lança uma DioException (antigo DioError) para qualquer problema: falta de rede, timeout, erros HTTP 4xx/5xx. Muitos desenvolvedores capturam apenas a Exception genérica, perdendo informações sobre o tipo de erro e a capacidade de tratá-lo especificamente. Use DioException.type para determinar a causa da falha.
Ignorar CancelToken leva a vazamentos de requisições. Se um usuário sair de uma tela enquanto uma requisição ainda está em execução, o Dio desperdiça recursos e pode tentar atualizar um State destruído. Crie sempre um CancelToken para cada requisição e cancele-o em dispose(). O CancelToken gera uma DioException com tipo cancel, que deve ser tratada adequadamente.
Falta de lógica de repetição para falhas temporárias. Em dispositivos móveis, a rede frequentemente fica indisponível por um breve período. Implemente um interceptador com repetição automática de requisição em caso de timeout ou resposta 503/502. Use o RetryInterceptor do pacote dio_smart_retry ou escreva um interceptador personalizado com backoff exponencial entre as tentativas.
Perguntas frequentes
Dio fornece interceptadores, configuração global BaseOptions, FormData, progresso de upload e CancelToken. O pacote http da equipe Dart é minimalista, sem interceptadores ou configuração global. Dio é usado em projetos grandes, enquanto http é usado para scripts simples.
Por padrão, o Dio converte JSON para Map usando jsonDecode. Para serialização tipada, use os pacotes json_serializable ou freezed. Crie um interceptador personalizado que converta response.data em DTO através de fromJson() no onResponse.
Crie um CancelToken e passe-o nas opções da requisição. Chamar token.cancel() interrompe a requisição e lança uma DioException com tipo cancel. O CancelToken suporta o cancelamento de múltiplas requisições simultaneamente, o que é conveniente para cancelar todas as requisições ao sair de uma tela.
Sim, o Dio funciona em todas as seis plataformas Flutter: Android, iOS, Web, macOS, Windows e Linux. Cada plataforma usa um cliente HTTP adaptativo: DartNativeAdapter (plataformas nativas) e BrowserAdapter (Web). Uma API unificada para todas as plataformas é uma vantagem chave do Dio em projetos Flutter.
O Dio não gerencia cookies automaticamente. Para suporte a cookies, use o pacote dio_cookie_manager junto com cookie_jar. O CookieManager intercepta os cabeçalhos Set-Cookie e Cookie e salva os cookies no PersistCookieJar para envio automático em requisições subsequentes ao mesmo domínio.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também