← Назад к вопросам

Какие знаешь HTTP клиенты?

1.3 Junior🔥 191 комментариев
#Работа с сетью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

HTTP клиенты в Dart/Flutter

HTTP клиент — это библиотека для выполнения HTTP запросов (GET, POST, PUT, DELETE и т.д.) к веб-сервисам и API. В Dart и Flutter существует несколько популярных вариантов, каждый со своими преимуществами.

1. http (официальный пакет Dart)

import 'package:http/http.dart' as http;

// GET запрос
Future<List<User>> fetchUsers() async {
  final response = await http.get(
    Uri.parse('https://api.example.com/users'),
  );
  
  if (response.statusCode == 200) {
    final jsonData = jsonDecode(response.body) as List;
    return jsonData.map((item) => User.fromJson(item)).toList();
  } else {
    throw Exception('Failed to load users: ${response.statusCode}');
  }
}

// POST запрос
Future<User> createUser(String name, String email) async {
  final response = await http.post(
    Uri.parse('https://api.example.com/users'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({'name': name, 'email': email}),
  );
  
  if (response.statusCode == 201) {
    return User.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to create user');
  }
}

Преимущества:

  • Официальный пакет от Dart команды
  • Простой в использовании
  • Минималистичный API

Недостатки:

  • Нет встроенной поддержки interceptors
  • Нет retry механизма

2. dio (самый популярный)

import 'package:dio/dio.dart';

class ApiClient {
  late final Dio _dio;
  
  ApiClient() {
    _dio = Dio(BaseOptions(
      baseUrl: 'https://api.example.com',
      connectTimeout: Duration(seconds: 10),
      receiveTimeout: Duration(seconds: 10),
    ));
    
    _dio.interceptors.add(LoggingInterceptor());
    _dio.interceptors.add(ErrorInterceptor());
  }
  
  Future<List<User>> fetchUsers() async {
    try {
      final response = await _dio.get('/users');
      final data = response.data as List;
      return data.map((item) => User.fromJson(item)).toList();
    } on DioException catch (e) {
      print('Error: ${e.message}');
      rethrow;
    }
  }
  
  Future<User> createUser(String name, String email) async {
    final response = await _dio.post(
      '/users',
      data: {'name': name, 'email': email},
    );
    return User.fromJson(response.data);
  }
  
  Future<void> downloadFile(String fileUrl, String savePath) async {
    await _dio.download(
      fileUrl,
      savePath,
      onReceiveProgress: (received, total) {
        print('Progress: ${(received / total * 100).toStringAsFixed(0)}%');
      },
    );
  }
}

class LoggingInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    print('REQUEST: ${options.method} ${options.path}');
    handler.next(options);
  }
  
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    print('RESPONSE: ${response.statusCode}');
    handler.next(response);
  }
}

Преимущества:

  • Полная функциональность (timeout, retry, interceptors)
  • Поддержка загрузки файлов
  • Отличная документация
  • Множество готовых интеграций

3. Chopper (генерация кода)

import 'package:chopper/chopper.dart';

part 'api_client.chopper.dart';

@ChopperApi(baseUrl: 'https://api.example.com')
abstract class ApiClient extends ChopperService {
  @Get(path: '/users')
  Future<Response<List<User>>> fetchUsers();
  
  @Post(path: '/users')
  Future<Response<User>> createUser(@Body() Map<String, dynamic> body);
  
  @Put(path: '/users/{id}')
  Future<Response<User>> updateUser(
    @Path('id') String id,
    @Body() Map<String, dynamic> body,
  );
  
  @Delete(path: '/users/{id}')
  Future<Response<void>> deleteUser(@Path('id') String id);
}

Преимущества:

  • Типизированный API через аннотации
  • Генерация кода
  • Меньше boilerplate кода

4. retrofit (для REST API)

import 'package:retrofit/retrofit.dart';
import 'package:dio/dio.dart';

part 'api_client.g.dart';

@RestApi(baseUrl: 'https://api.example.com')
abstract class ApiClient {
  factory ApiClient(Dio dio, {String baseUrl}) = _ApiClient;
  
  @GET('/users')
  Future<List<User>> fetchUsers();
  
  @POST('/users')
  Future<User> createUser(@Body() User user);
  
  @GET('/users/{id}')
  Future<User> getUserById(@Path('id') String id);
  
  @PUT('/users/{id}')
  Future<User> updateUser(
    @Path('id') String id,
    @Body() User user,
  );
  
  @DELETE('/users/{id}')
  Future<void> deleteUser(@Path('id') String id);
  
  @GET('/search')
  Future<List<User>> searchUsers(@Query('q') String query);
}

Преимущества:

  • Декларативный синтаксис
  • Автоматическое преобразование типов
  • Очень похож на Retrofit в Android

5. graphql (для GraphQL)

import 'package:graphql/client.dart';

class GraphQLApiClient {
  late GraphQLClient _client;
  
  GraphQLApiClient() {
    final httpLink = HttpLink('https://api.example.com/graphql');
    final authLink = AuthLink(
      getToken: () async => 'Bearer YOUR_TOKEN',
    );
    
    final link = authLink.concat(httpLink);
    
    _client = GraphQLClient(
      cache: GraphQLCache(),
      link: link,
    );
  }
  
  Future<Map<String, dynamic>> fetchUsers() async {
    const String query = 'query GetUsers { users { id name email } }';
    
    final result = await _client.query(
      QueryOptions(document: gql(query)),
    );
    
    if (result.hasException) {
      throw Exception(result.exception);
    }
    
    return result.data!;
  }
  
  Future<Map<String, dynamic>> createUser(String name, String email) async {
    const String mutation = 'mutation CreateUser { createUser(name, email) { id } }';
    
    final result = await _client.mutate(
      MutationOptions(
        document: gql(mutation),
        variables: {'name': name, 'email': email},
      ),
    );
    
    if (result.hasException) {
      throw Exception(result.exception);
    }
    
    return result.data!;
  }
}

Сравнение HTTP клиентов

КлиентСложностьФункцииGraphQLРекомендация
httpПростаяБазовыеНетПростые проекты
dioСредняяПолнаяНетБольшинство проектов
chopperСредняяПолнаяНетREST API с кодогенерацией
retrofitСредняяПолнаяНетREST API (Android-like)
graphqlСложнаяGraphQLДаGraphQL API

Best Practices

// 1. Используй dio для большинства случаев
final dio = Dio(BaseOptions(
  connectTimeout: Duration(seconds: 10),
  receiveTimeout: Duration(seconds: 10),
  headers: {'Authorization': 'Bearer token'},
));

// 2. Добавляй interceptors для обработки ошибок
dio.interceptors.add(ErrorInterceptor());

// 3. Используй типизацию
Future<User> getUser(String id) async {
  final response = await dio.get('/users/$id');
  return User.fromJson(response.data);
}

// 4. Обрабатывай ошибки правильно
try {
  final users = await fetchUsers();
} on DioException catch (e) {
  if (e.type == DioExceptionType.connectionTimeout) {
    print('Connection timeout');
  } else if (e.response?.statusCode == 404) {
    print('Not found');
  } else {
    print('Error: ${e.message}');
  }
}

Как выбрать клиент

http — если нужно минимально зависимостей и простота dio — стандартный выбор для большинства проектов retrofit — если работаешь с REST API и привык к Android graphql — если API построен на GraphQL chopper — если предпочитаешь кодогенерацию

Заключение

Большинство профессиональных Flutter приложений используют dio благодаря его мощности, гибкости и хорошей документации. Он позволяет работать с любыми API, имеет встроенную поддержку interceptors, обработку ошибок и загрузку файлов.

Какие знаешь HTTP клиенты? | PrepBro