Что такое multipart/form-data в контексте HTTP-запросов?

Ответ

multipart/form-data — это тип содержимого (Content-Type) для кодирования данных HTML-форм при отправке через HTTP. Он позволяет передавать в одном запросе как текстовые поля, так и бинарные файлы (изображения, документы и т.д.).

Как это работает: Запрос разбивается на несколько «частей» (parts), разделённых уникальной строкой-границей (boundary). Каждая часть содержит свои заголовки (например, Content-Disposition с именем поля) и тело с данными.

Пример отправки файла и текста в Flutter/Dart с пакетом http:

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

Future<void> uploadImage(String imagePath, String description) async {
  var request = http.MultipartRequest(
    'POST',
    Uri.parse('https://api.example.com/upload'),
  );

  // Добавляем файл
  request.files.add(
    await http.MultipartFile.fromPath(
      'image', // Имя поля формы
      imagePath,
      contentType: MediaType('image', 'jpeg'),
    ),
  );

  // Добавляем текстовое поле
  request.fields['description'] = description;

  try {
    final response = await request.send();
    if (response.statusCode == 200) {
      print('Файл успешно загружен');
    } else {
      print('Ошибка: ${response.statusCode}');
    }
  } catch (e) {
    print('Ошибка сети: $e');
  }
}

Когда использовать:

  • Загрузка файлов на сервер.
  • Отправка форм, содержащих смешанные данные (текст + файлы).
  • Реализация API, аналогичного поведению HTML-формы с атрибутом enctype="multipart/form-data".

Ответ 18+ 🔞

А, ну это же классика, ёпта! multipart/form-data — это такой специальный контент-тайп, когда тебе надо отправить на сервер не просто текстовую записку, а целый набор: и текст, и файлы в одном флаконе. Представь, будто ты не просто пишешь письмо, а прикладываешь к нему фотку своей собаки и квитанцию за квартиру — вот это оно и есть.

Как эта штука устроена, если без заумностей: Запрос делится на куски, как торт на дне рождения. Между кусками — уникальная разделительная полоска (boundary). В каждом куске свои метаданные (типа, «это фотка, зовут Барсик») и само содержимое. Сервер потом это всё аккуратно разбирает.

Вот тебе живой пример на Dart/Flutter с пакетом http. Смотри, как это просто:

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

Future<void> uploadImage(String imagePath, String description) async {
  // Создаём запрос, как будто форму на сайте заполняем
  var request = http.MultipartRequest(
    'POST',
    Uri.parse('https://api.example.com/upload'),
  );

  // Цепляем файлик. 'image' — это имя поля, куда его суём.
  request.files.add(
    await http.MultipartFile.fromPath(
      'image',
      imagePath,
      contentType: MediaType('image', 'jpeg'),
    ),
  );

  // А тут обычное текстовое поле, типа комментария
  request.fields['description'] = description;

  try {
    // Поехали, отправляем!
    final response = await request.send();
    if (response.statusCode == 200) {
      print('Файл успешно загружен');
    } else {
      print('Ошибка: ${response.statusCode}');
    }
  } catch (e) {
    // Ну тут всё понятно, сеть — она такая, хитрая жопа
    print('Ошибка сети: $e');
  }
}

Когда эту банду multipart/form-data вызывать на дело:

  • Загрузка файлов на сервер — фотки, документы, что угодно. Без этого — никуда.
  • Отправка сложных форм, где вперемешку и текст, и файлы. Как та самая HTML-форма с enctype="multipart/form-data".
  • Когда пишешь API, которое должно понимать такие же запросы, как браузер. В общем, стандартная история, но доверия к ней, блядь, ноль, если не проверишь границу (boundary) дважды.