Flutter HTTP-запрос

В этом разделе будет рассказано, как выполнять сетевые HTTP-запросы в приложениях Flutter, включая GET- и POST-запросы, а также обработку данных JSON.


Добавление HTTP-зависимости

Добавьте пакет http в pubspec.yaml:

dependencies:
  http: ^1.0.0

Затем выполните:

$ flutter pub get

Отправить GET-запрос

Пример: GET-запрос

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

// Простой GET-запрос
Future<void> fetchData() async {
  final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

  if (response.statusCode == 200) {
    // Парсинг данных JSON
    final data = jsonDecode(response.body);
    print('Заголовок: ${data['title']}');
  } else {
    print('Ошибка запроса: ${response.statusCode}');
  }
}

// GET-запрос с параметрами
Future<void> searchData(String query) async {
  final uri = Uri.parse('https://api.example.com/search')
      .replace(queryParameters: {'q': query, 'page': '1'});

  final response = await http.get(uri);

  if (response.statusCode == 200) {
    final data = jsonDecode(response.body);
    print(Результат: $data);
  }
}

Отправить POST-запрос

Пример: POST-запрос

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

// POST-запрос — отправка данных JSON
Future<void> postData() async {
  final uri = Uri.parse('https://jsonplaceholder.typicode.com/posts');

  final response = await http.post(
    uri,
    headers: {
      'Content-Type': 'application/json',  // Установить заголовок запроса
    },
    body: jsonEncode({  // Преобразовать объект Dart в строку JSON
      'title': Руководство по Flutter,
      'body': 'Изучение сетевых запросов во Flutter',
      'userId': 1,
    }),
  );

  if (response.statusCode == 201) {
    final data = jsonDecode(response.body);
    print('Успешно создано: $data');
  } else {
    print('Ошибка запроса: ${response.statusCode}');
  }
}

// POST-запрос - отправка данных формы
Future<void> postFormData() async {
  final uri = Uri.parse('https://example.com/api/login');

  final response = await http.post(
    uri,
    body: {
      'username': 'admin',
      'password': '123456',
    },
  );

  print('Ответ: ${response.body}');
}

Обработка данных JSON

Пример: парсинг JSON

import 'dart:convert';

// Определить модель данных
class Article {
  final int id;
  final String title;
  final String body;
  final User user;

  Article({
    required this.id,
    required this.title,
    required this.body,
    required this.user,
  });

  // Разобрать из JSON
  factory Article.fromJson(Map<String, dynamic> json) {
    return Article(
      id: json['id'],
      title: json['title'],
      body: json['body'],
      user: User.fromJson(json['user']),
    );
  }

  // Преобразовать в JSON
  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'body': body,
      'user': user.toJson(),
    };
  }
}

class User {
  final int id;
  final String name;

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

  factory User.fromJson(Map<String, dynamic> json) {
    return User(id: json['id'], name: json['name']);
  }

  Map<String, dynamic> toJson() {
    return {'id': id, 'name': name};
  }
}

// Пример использования
void parseJson() {
  final jsonString = '''
  {
    "id": 1,
"title": "Учебник по Flutter",
"body": "Изучите Flutter",
"user": {"id": 1, "name": "Чжан Сань"}
  }
  '
'';

  // Разбор строки JSON
  final Map<String, dynamic> json = jsonDecode(jsonString);
  final article = Article.fromJson(json);

  print('ID статьи: ${article.id}');
  print('Автор: ${article.user.name}');
}

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

Пример: Полный пример сетевого запроса

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

class ApiService {
  // Базовый URL
  static const String baseUrl = 'https://jsonplaceholder.typicode.com';

  // Универсальный метод GET-запроса
  static Future<dynamic> get(String endpoint) async {
    try {
      final response = await http.get(
        Uri.parse('$baseUrl/$endpoint'),
      );
      return _handleResponse(response);
    } catch (e) {
      throw ApiException('Ошибка сети: $e');
    }
  }

  // Универсальный метод POST-запроса
  static Future<dynamic> post(
    String endpoint,
    Map<String, dynamic> data,
  ) async {
    try {
      final response = await http.post(
        Uri.parse('$baseUrl/$endpoint'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode(data),
      );
      return _handleResponse(response);
    } catch (e) {
      throw ApiException('Ошибка сети: $e');
    }
  }

  // Обработка ответа
  static dynamic _handleResponse(http.Response response) {
    if (response.statusCode >= 200 && response.statusCode < 300) {
      // Успешный ответ
      if (response.body.isEmpty) {
        return null;
      }
      return jsonDecode(response.body);
    } else if (response.statusCode == 404) {
      throw ApiException(Ресурс не найден, statusCode: 404);
    } else if (response.statusCode >= 500) {
      throw ApiException('Ошибка сервера', statusCode: response.statusCode);
    } else {
      throw ApiException(
        'Запрос не выполнен',
        statusCode: response.statusCode,
      );
    }
  }
}

// Пользовательский класс исключения
class ApiException implements Exception {
  final String message;
  final int? statusCode;

  ApiException(this.message, {this.statusCode});

  @override
  String toString() => 'ApiException: $message (статус: $statusCode)';
}

// Пример использования
Future<void> fetchArticles() async {
  try {
    final articles = await ApiService.get('posts');
    print('Получено ${articles.length} статей');
  } on ApiException catch (e) {
    print('API error: $e');
  }
}

В реальных приложениях рекомендуется инкапсулировать сетевые запросы в сервисные классы, чтобы единообразно обрабатывать ошибки, состояния загрузки и логику кэширования.

Другие расширения