Как отправить файл в теле POST-запроса в Flutter/Dart?

«Как отправить файл в теле POST-запроса в Flutter/Dart?» — вопрос из категории Сети, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для отправки файла в POST-запросе в Dart/Flutter я обычно использую пакет http или dio. dio часто удобнее для сложных сценариев, но http подходит для базовых задач. Вот пример с http:

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

Future<http.StreamedResponse> uploadFile(String filePath) async {
  var uri = Uri.parse('https://api.example.com/upload');
  var request = http.MultipartRequest('POST', uri);

  // Добавляем файл из локального пути
  request.files.add(
    await http.MultipartFile.fromPath(
      'file', // Имя поля формы, должно совпадать с ожиданиями сервера
      filePath,
      contentType: MediaType('image', 'jpeg'), // Указываем MIME-тип
      filename: path.basename(filePath), // Можно явно задать имя файла
    ),
  );

  // Можно добавить дополнительные текстовые поля
  request.fields['userId'] = '12345';
  request.fields['description'] = 'Profile picture';

  // Отправляем запрос и получаем StreamedResponse
  var response = await request.send();
  return response;
}

Ключевые моменты:

  • MultipartRequest — специальный класс для создания запросов с данными формы (multipart/form-data), которые могут содержать файлы.
  • MultipartFile.fromPath() — удобный метод для создания части запроса из файла в файловой системе устройства.
  • contentType — важно указывать корректный MIME-тип (например, MediaType('application', 'pdf') для PDF), чтобы сервер мог правильно обработать файл.
  • Имя поля 'file' — это ключ, по которому сервер будет искать файл. Его нужно согласовывать с бэкенд-разработчиками.

С пакетом dio это выглядит еще лаконичнее:

import 'package:dio/dio.dart';

Future<void> uploadFileWithDio(String filePath) async {
  var dio = Dio();
  FormData formData = FormData.fromMap({
    'file': await MultipartFile.fromFile(filePath, filename: 'photo.jpg'),
    'userId': '12345',
  });
  var response = await dio.post('https://api.example.com/upload', data: formData);
  print(response.data);
}