Веб

urlencoded vs multipart/form-data в API: когда использовать

Сравнение application/x-www-form-urlencoded и multipart/form-data для API post запросов. Рекомендации по размеру данных, не-ASCII символам, двоичным данным и метаданным. Примеры curl, fetch, Python requests.

Когда использовать application/x-www-form-urlencoded vs multipart/form-data в разработке API?

В HTTP существуют два основных типа содержимого для POST-данных: application/x-www-form-urlencoded и multipart/form-data. Хотя я понимаю, что браузеры обычно требуют multipart/form-data для загрузки файлов, мне нужна рекомендация по выбору каждого типа кодирования в контексте API (без участия браузеров).

Можете ли вы предоставить рекомендации на основе следующих факторов:

  • Рассмотрения размера данных
  • Обработка не-ASCII символов
  • Передача двоичных данных
  • Необходимость в дополнительных метаданных (например, имен файлов)

Я не нашел исчерпывающих формальных рекомендаций по соответствующим случаям использования этих различных типов содержимого в разработке API.

В API post запросах выбор между application/x-www-form-urlencoded и multipart/form-data определяется типом и объёмом данных: для простых пар «ключ‑значение» и небольшого текстового контента (включая UTF‑8) обычно выгоднее application/x-www-form-urlencoded, а для файлов, больших двоичных payload и когда нужны метаданные (имя файла, Content-Type) — multipart/form-data. Учитывайте, что percent‑кодирование увеличивает размер для не‑ASCII и бинарных данных, а multipart добавляет MIME‑заголовки — нужно сопоставить накладные расходы и удобство обработки. Если данные структурированные (JSON) — чаще проще отправлять application/json, а не форму.


Содержание


Когда использовать application/x-www-form-urlencoded

Коротко: когда клиент отправляет только текстовые пары «ключ=значение», без файлов и без необходимости хранить per‑part метаданные — выбирайте application/x-www-form-urlencoded. Формат выглядит как query‑string: name1=value1&name2=value2; все «особые» байты кодируются в %HH (percent‑encoding). Это простой, широко совместимый вариант для POST‑форм и API, которые ожидают form‑encoded данные.

Когда это удобно

  • Небольшие формы и параметры (логин, токены, короткие поля).
  • Много маленьких полей, где накладные MIME‑заголовки будут ощутимее, чем единственная строка.
  • Требуется совместимость с устаревшими интеграциями/сервисами, которые принимают только form‑encoded.

О чём помнить

  • Percent‑кодирование применимо и к UTF‑8: сначала текст кодируется в байты UTF‑8, затем байты превращаются в %HH. Это работает, но увеличивает длину тела (особенно для кириллицы и других много‑байтовых наборов).
  • Для явного указания кодировки можно использовать заголовок Content‑Type: application/x-www-form-urlencoded; charset=UTF-8 — но поддержку параметра charset лучше проверять на стороне сервера/фреймворка.
  • Если API ожидает структурированные данные (сложные JSON‑объекты), application/json обычно удобнее и эффективнее.

Источник по синтаксису и примерам POST — см. документацию MDN: https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST и краткое сравнение форматов в примере‑gist: https://gist.github.com/joyrexus/524c7e811e4abf9afe56.


Когда использовать multipart/form-data

Коротко: когда нужно передать файлы или другие двоичные данные, либо каждую часть нужно снабдить собственными заголовками/метаданными — используйте multipart/form-data. Формат разбивает тело на части, разделённые boundary; каждая часть имеет свои HTTP‑заголовки (например, Content-Disposition и Content-Type).

Когда это удобно

  • Загрузка файлов (изображения, архивы, двоичные blobs).
  • Сценарии, где поле должно иметь своё имя файла (filename) и/или Content‑Type.
  • Когда нужен стриминг больших файлов (сервер может обрабатывать части по мере прихода).

О чём помнить

  • В заголовке Content‑Type указывается boundary (Content-Type: multipart/form-data; boundary=----XYZ). Клиентские библиотеки (curl -F, формы браузера, библиотеки multipart) обычно генерируют безопасный случайный boundary.
  • Для двоичных данных multipart избегает %‑кодирования — это делает его эффективным для больших файлов. Но у него есть MIME‑накладные на каждую часть, поэтому для множества мелких полей это может быть менее выгодно.
  • Кодировка файловых имён и текстовых частей иногда вызывает нюансы; используйте UTF‑8 и проверяйте поддержку на клиенте/сервере.

Технические детали и разъяснения формата — см. статью на Wikipedia: https://ru.wikipedia.org/wiki/Multipart/form-data и обзор структуры на Habr: https://habr.com/ru/articles/511114/.


Сравнение по факторам: размер, не‑ASCII, двоичные данные, метаданные

Размер данных

  • application/x-www-form-urlencoded: хорош для небольших и средних текстовых наборов. Percent‑кодирование добавляет накладные байты, особенно для нелатиницы и бинарных данных (каждый байт превращается в %HH).
  • multipart/form-data: добавляет MIME‑заголовки для каждой части (Content‑Disposition, Content‑Type и др.). Для одного большого файла общая накладная часть мала по сравнению с увеличением, которое дал бы urlencoding бинарного файла; для множества мелких полей — overhead может быть заметен.

Вывод: много мелких текстовых полей → чаще urlencoded; большие файлы/бинар → multipart.

Не‑ASCII символы и кодировка

  • В urlencoded: текст сначала кодируется в байты (обычно UTF‑8), затем байты percent‑кодуются. Работает, но тело увеличивается; для больших объёмов текста лучше использовать application/json или multipart с явным charset.
  • В multipart: каждая часть может иметь свой заголовок Content‑Type, например text/plain; charset=UTF-8 — то есть можно посылать UTF‑8 напрямую в теле части без percent‑кодирования.

Итого: оба варианта поддерживают UTF‑8, но multipart даёт более явный контроль над кодировкой в каждой части.

Двоичные данные

  • urlencoded: возможна передача бинарных данных (через percent‑encoding или base64), но это крайне неэффективно.
  • multipart: предназначен для двоичных частей — файл передаётся «как есть», с указанием Content‑Type. Для больших бинарных файлов multipart почти всегда предпочтительнее.

Если по каким‑то причинам multipart нельзя, возможна альтернатива: base64 в JSON/филдe, но размер вырастет примерно на ~33% и теряется потоковая обработка; обычно это компромисс хуже, чем multipart.

Метаданные и имена файлов

  • urlencoded: нет механизма передачи per‑file metadata (имя файла, mime‑тип) как части тела — можно передать дополнительные поля с именем строки, но это не заменит стандартных заголовков.
  • multipart: стандартно поддерживает Content‑Disposition с параметром filename и Content‑Type для каждой части, что делает его естественным выбором при необходимости передавать метаданные вместе с двоичными данными.

Учтите нюансы кодирования имён файлов в заголовках и совместимость разных клиентов/серверов — библиотеки обычно решают это за вас.


Примеры: curl, fetch, Python requests

Ниже — минимальные шаблоны для клиента (без браузера).

application/x-www-form-urlencoded (curl):

bash
curl -X POST "https://api.example.com/endpoint" \
 -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
 --data-urlencode "username=Иван" \
 --data-urlencode "message=Привет, мир!"

application/x-www-form-urlencoded (fetch, Node/JS):

javascript
const params = new URLSearchParams();
params.append('username', 'Иван');
params.append('message', 'Привет, мир!');

fetch('https://api.example.com/endpoint', {
 method: 'POST',
 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
 body: params.toString()
});

multipart/form-data (curl — файл + поля):

bash
curl -X POST "https://api.example.com/upload" \
 -F "file=@./photo.jpg;type=image/jpeg" \
 -F "title=Фото с отпуска"

(-F автоматически формирует Content-Type: multipart/form-data; boundary=…)

multipart/form-data (Python requests):

python
import requests

files = {'file': ('photo.jpg', open('photo.jpg', 'rb'), 'image/jpeg')}
data = {'title': 'Фото с отпуска'}
resp = requests.post('https://api.example.com/upload', files=files, data=data)

Если нужно отправить JSON‑метаданные + файл — проще сделать multipart, где одна часть имеет Content-Type: application/json (или положить JSON как отдельное поле).

Полезная шпаргалка и сравнение режимов в Postman/клиентах — см. обсуждение на StackOverflow: https://stackoverflow.com/questions/26723467/postman-chrome-what-is-the-difference-between-form-data-x-www-form-urlencoded.


Практические советы и распространённые ошибки

  • Если API предназначен для структурированных данных — отдавайте предпочтение application/json. Form‑encoding и multipart нужны для совместимости и/или файлов. (Обсуждение практичности multipart для REST — https://stackoverflow.com/questions/30364642/does-using-multipart-form-data-content-type-for-a-restful-post-api-a-good-practi.)
  • Проверяйте и валидацию Content‑Type на сервере. Не полагайтесь на клиентские заголовки без проверки.
  • Ограничьте размер загружаемых файлов и используйте стриминг на сервере, чтобы не держать весь файл в памяти.
  • Для передачи файлов между API и сервисами используйте multipart; не присылайте файлы в urlencoded и не храните двоичные данные в строковых полях.
  • Тестируйте кодировку имён файлов и текстовых полей — разные клиенты/серверы по‑разному работают с заголовками и charset.
  • Если в интеграции участвуют 1С или другие специфичные платформы, проверьте их требования к Content‑Type (частые кейсы: multipart/form-data 1с).
  • Для отладки удобно смотреть «сырое» тело запроса; curl -v и специальные утилиты покажут границы и заголовки.

Короткий чек‑лист при выборе:

  • Есть файлы/бинар → multipart/form-data.
  • Только параметры и маленький текст → application/x-www-form-urlencoded (или лучше — application/json).
  • Нужны имена файлов и mime‑типы → multipart.
  • Большой текст (не‑ASCII) → подумайте про JSON или multipart с charset.

Источники

  1. https://developer.mozilla.org/ru/docs/Web/HTTP/Methods/POST
  2. https://ru.wikipedia.org/wiki/Multipart/form-data
  3. https://habr.com/ru/articles/511114/
  4. https://gist.github.com/joyrexus/524c7e811e4abf9afe56
  5. https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data
  6. https://stackoverflow.com/questions/26723467/postman-chrome-what-is-the-difference-between-form-data-x-www-form-urlencoded
  7. https://stackoverflow.com/questions/30364642/does-using-multipart-form-data-content-type-for-a-restful-post-api-a-good-practi
  8. https://medium.com/@codingscenes/application-x-www-form-urlencoded-and-multipart-form-data-are-two-different-formats-for-3678a10073e9

Заключение

Выбор между application/x-www-form-urlencoded и multipart/form-data для API сводится к одному вопросу: нужно ли отправлять файлы/бинар и per‑part метаданные? Если да — multipart/form-data; если нет — чаще удобнее application/x-www-form-urlencoded (для простых полей) или ещё лучше application/json для структурированных payload. Учтите рост размера из‑за percent‑кодирования у urlencoded и накладные MIME‑заголовки у multipart; тестируйте на реальных объёмах и используйте проверенные парсеры на сервере.

Авторы
Проверено модерацией
Модерация
urlencoded vs multipart/form-data в API: когда использовать