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

Как выполнять сетевые запросы во Flutter?

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

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

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

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

Сетевые запросы во Flutter

Встроенный пакет http

http — это встроенный пакет Flutter для выполнения HTTP запросов. Это простой и лёгкий способ:

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

// GET запрос
Future<void> fetchUserData() async {
  try {
    final response = await http.get(
      Uri.parse("https://api.example.com/users/1"),
      headers: {
        "Authorization": "Bearer token",
        "Content-Type": "application/json",
      },
    );

    if (response.statusCode == 200) {
      print(response.body);
    } else {
      print("Error: ${response.statusCode}");
    }
  } catch (e) {
    print("Error: $e");
  }
}

// POST запрос
Future<void> createUser() async {
  final response = await http.post(
    Uri.parse("https://api.example.com/users"),
    headers: {"Content-Type": "application/json"},
    body: jsonEncode({
      "name": "John",
      "email": "john@example.com",
    }),
  );

  if (response.statusCode == 201) {
    print("User created");
  }
}

// DELETE запрос
Future<void> deleteUser(String id) async {
  final response = await http.delete(
    Uri.parse("https://api.example.com/users/$id"),
  );
  print(response.statusCode);
}

Dio — более мощная альтернатива

Dio имеет больше функций: перехватчики (interceptors), таймауты, отмену запросов:

import "package:dio/dio.dart";

final dio = Dio(
  BaseOptions(
    baseUrl: "https://api.example.com",
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 3),
    headers: {"Authorization": "Bearer token"},
  ),
);

// GET запрос
Future<void> fetchUsers() async {
  try {
    final response = await dio.get("/users");
    print(response.data); // Автоматически парсит JSON
  } on DioException catch (e) {
    print("Error: ${e.message}");
  }
}

// POST с параметрами
Future<void> createUser(String name, String email) async {
  final response = await dio.post(
    "/users",
    data: {"name": name, "email": email},
  );
  print(response.data);
}

// Отмена запроса
final cancelToken = CancelToken();
await dio.get("/users", cancelToken: cancelToken);
cancelToken.cancel("Request cancelled");

Перехватчики (Interceptors) в Dio

dio.interceptors.add(
  InterceptorsWrapper(
    onRequest: (options, handler) {
      // Модифицировать запрос перед отправкой
      print("Sending request to: ${options.path}");
      return handler.next(options);
    },
    onResponse: (response, handler) {
      // Обработать ответ
      print("Response: ${response.statusCode}");
      return handler.next(response);
    },
    onError: (DioException e, handler) {
      // Обработать ошибку
      print("Error: ${e.message}");
      return handler.next(e);
    },
  ),
);

Работа с JSON

import "dart:convert";

class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  // Из JSON
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json["id"],
      name: json["name"],
      email: json["email"],
    );
  }

  // В JSON
  Map<String, dynamic> toJson() => {
    "id": id,
    "name": name,
    "email": email,
  };
}

// Использование
Future<User> fetchUser(int id) async {
  final response = await http.get(
    Uri.parse("https://api.example.com/users/$id"),
  );

  if (response.statusCode == 200) {
    return User.fromJson(jsonDecode(response.body));
  } else {
    throw Exception("Failed to load user");
  }
}

// Список объектов
Future<List<User>> fetchUsers() async {
  final response = await http.get(
    Uri.parse("https://api.example.com/users"),
  );

  if (response.statusCode == 200) {
    final List<dynamic> data = jsonDecode(response.body);
    return data.map((json) => User.fromJson(json)).toList();
  } else {
    throw Exception("Failed to load users");
  }
}

Интеграция с BLoC

class UserBloc extends Bloc<UserEvent, UserState> {
  final ApiService apiService;

  UserBloc(this.apiService) : super(UserInitial()) {
    on<FetchUserEvent>(_onFetchUser);
  }

  Future<void> _onFetchUser(
    FetchUserEvent event,
    Emitter<UserState> emit,
  ) async {
    emit(UserLoading());
    try {
      final user = await apiService.fetchUser(event.userId);
      emit(UserLoaded(user));
    } catch (e) {
      emit(UserError(e.toString()));
    }
  }
}

// В UI
class UserPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<UserBloc, UserState>(
      builder: (context, state) {
        if (state is UserLoading) {
          return CircularProgressIndicator();
        } else if (state is UserLoaded) {
          return Text(state.user.name);
        } else if (state is UserError) {
          return Text("Error: ${state.message}");
        }
        return SizedBox();
      },
    );
  }
}

Авторизация и заголовки

class ApiService {
  final Dio dio;

  ApiService(this.dio) {
    _setupInterceptors();
  }

  void _setupInterceptors() {
    dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          // Добавить токен к каждому запросу
          final token = await _getToken();
          options.headers["Authorization"] = "Bearer $token";
          return handler.next(options);
        },
        onError: (DioException e, handler) async {
          // Обновить токен при ошибке 401
          if (e.response?.statusCode == 401) {
            try {
              await _refreshToken();
              return handler.resolve(
                await _retry(e.requestOptions),
              );
            } catch (_) {
              return handler.next(e);
            }
          }
          return handler.next(e);
        },
      ),
    );
  }

  Future<String> _getToken() async {
    // Получить токен из SharedPreferences
    return "token";
  }

  Future<void> _refreshToken() async {
    // Обновить токен на сервере
  }

  Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {
    final options = Options(
      method: requestOptions.method,
      headers: requestOptions.headers,
    );
    return dio.request<dynamic>(
      requestOptions.path,
      data: requestOptions.data,
      queryParameters: requestOptions.queryParameters,
      options: options,
    );
  }
}

REST API рекомендации

  • GET — получение данных
  • POST — создание ресурса
  • PUT/PATCH — обновление ресурса
  • DELETE — удаление ресурса

Обработка ошибок

Future<void> safeApiCall() async {
  try {
    final response = await dio.get("/users");
    // Успех
  } on DioException catch (e) {
    if (e.type == DioExceptionType.connectionTimeout) {
      print("Connection timeout");
    } else if (e.type == DioExceptionType.receiveTimeout) {
      print("Receive timeout");
    } else if (e.response?.statusCode == 404) {
      print("Not found");
    } else if (e.response?.statusCode == 500) {
      print("Server error");
    }
  } catch (e) {
    print("Unknown error: $e");
  }
}

Итог

  • http — для простых GET запросов
  • Dio — для сложных приложений с авторизацией и перехватчиками
  • Всегда типизируйте JSON-ответы (User, Post и т.д.)
  • Обрабатывайте ошибки и таймауты
  • Интегрируйте с BLoC для управления состоянием
Как выполнять сетевые запросы во Flutter? | PrepBro