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

Как передать бинарный файл в POST?

2.0 Middle🔥 261 комментариев
#API и интеграции#Форматы данных и протоколы

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

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

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

Передача бинарных файлов в POST: технические подходы

Передача бинарных файлов (изображения, документы, видео, архивы) — частая задача в API. Существует несколько подходов, каждый с преимуществами и недостатками.

Подход 1: multipart/form-data (Рекомендуется)

Описание

Это стандартный способ передачи файлов через формы в HTML и API. Данные кодируются как multipart MIME-сообщение.

Пример HTTP запроса:

POST /api/v1/upload HTTP/1.1
Host: api.example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
Content-Length: 12345

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg

[BINARY DATA HERE]
------WebKitFormBoundary
Content-Disposition: form-data; name="description"

My photo
------WebKitFormBoundary--

Преимущества:

  • Стандарт для загрузки файлов
  • Поддерживается везде (браузеры, curl, библиотеки)
  • Можно передать несколько файлов одновременно
  • Можно добавить дополнительные поля (метаданные)
  • Метаданные передаются отдельно от бинарных данных

Недостатки:

  • Больший overhead из-за boundary разделителей
  • Сложнее отладить вручную

Пример на разных языках:

curl:

curl -X POST http://localhost:3000/upload \
  -F "file=@photo.jpg" \
  -F "description=My photo"

Python (requests):

import requests

with open('photo.jpg', 'rb') as f:
    files = {'file': f}
    data = {'description': 'My photo'}
    response = requests.post('http://localhost:3000/upload', 
                            files=files, data=data)

JavaScript (fetch):

const formData = new FormData();
const fileInput = document.querySelector('input[type="file"]');
formData.append('file', fileInput.files[0]);
formData.append('description', 'My photo');

fetch('/api/v1/upload', {
  method: 'POST',
  body: formData
}).then(r => r.json());

FastAPI (Python):

from fastapi import FastAPI, UploadFile, File, Form

@app.post("/upload")
async def upload(file: UploadFile = File(...), 
                description: str = Form(...)):
    contents = await file.read()
    # Сохраняем файл
    return {"filename": file.filename, "size": len(contents)}

Подход 2: application/octet-stream (Raw binary)

Описание

Передача чистого бинарного содержимого без каких-либо оберток.

Пример HTTP запроса:

POST /api/v1/upload HTTP/1.1
Host: api.example.com
Content-Type: application/octet-stream
Content-Length: 1024

[BINARY DATA HERE]

Преимущества:

  • Минимальный overhead
  • Быстро и эффективно
  • Простая отладка (чистые бинарные данные)

Недостатки:

  • Нельзя передать метаданные в теле (только в headers)
  • Нельзя передать несколько файлов одновременно
  • Нужно передавать имя файла в заголовке

Пример:

curl:

curl -X POST http://localhost:3000/upload \
  -H "Content-Type: application/octet-stream" \
  -H "X-Filename: photo.jpg" \
  --data-binary @photo.jpg

FastAPI:

@app.post("/upload")
async def upload(request: Request):
    body = await request.body()
    filename = request.headers.get('X-Filename')
    # Сохраняем файл
    return {"filename": filename, "size": len(body)}

Подход 3: Base64 кодирование в JSON

Описание

Преобразование бинарных данных в Base64 строку и отправка в JSON.

Пример:

{
  "file": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
  "filename": "photo.jpg",
  "mimeType": "image/jpeg"
}

Преимущества:

  • Удобно для API, которые принимают JSON
  • Легко отправить из JavaScript
  • Все метаданные в одном JSON

Недостатки:

  • Base64 увеличивает размер на 33%
  • Медленнее чем бинарные данные
  • Много памяти для больших файлов

Пример:

JavaScript:

const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

const reader = new FileReader();
reader.onload = () => {
  const base64 = reader.result.split(',')[1];
  fetch('/api/v1/upload', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      file: base64,
      filename: file.name,
      mimeType: file.type
    })
  });
};
reader.readAsDataURL(file);

FastAPI:

import base64
from pydantic import BaseModel

class FileUpload(BaseModel):
    file: str  # base64
    filename: str
    mimeType: str

@app.post("/upload")
async def upload(data: FileUpload):
    binary_data = base64.b64decode(data.file)
    # Сохраняем файл
    return {"filename": data.filename, "size": len(binary_data)}

Подход 4: Chunked upload (для больших файлов)

Описание

Разбиение большого файла на маленькие части (chunks) и загрузка их последовательно.

Процесс:

1. Клиент инициирует upload → получает upload_id
2. Отправляет chunk 1 (1MB)
3. Отправляет chunk 2 (1MB)
4. Отправляет chunk 3 (1MB)
...
N. Завершает upload → сервер объединяет chunks

Преимущества:

  • Можно загрузить файлы > памяти сервера
  • Resume capability (если разорвалось соединение)
  • Лучше для нестабильной сети
  • Показывать progress bar

Пример API:

Шаг 1. POST /uploads → {"upload_id": "abc123"}
Шаг 2. PUT /uploads/abc123/chunks/1 (бинарные данные)
Шаг 3. PUT /uploads/abc123/chunks/2 (бинарные данные)
...
Шаг N. POST /uploads/abc123/complete

Таблица сравнения подходов

Подход              | Размер файла | Сложность | Производительность
─────────────────────────────────────────────────────────────────
multipart/form-data | до 2-5GB     | Средняя   | Хорошая
application/octet   | до 2-5GB     | Простая   | Отличная
Base64 в JSON       | < 100MB      | Простая   | Плохая
Chunked upload      | Любой        | Высокая   | Хорошая

Best Practices для System Analyst

При проектировании API файлозагрузки:

1. Выберите правильный подход:

  • Файлы < 100MB + нужны метаданные → multipart/form-data
  • Файлы < 100MB + нет метаданных → octet-stream
  • Файлы < 5MB + JavaScript от браузера → Base64 в JSON
  • Файлы > 500MB → Chunked upload

2. Безопасность:

- Валидируй MIME-type (не доверяй расширению)
- Устанавливай лимит на размер файла
- Сканируй на вирусы
- Сохраняй в безопасном месте (вне web root)
- Проверь права доступа при скачивании

3. Производительность:

- Не загружай в память (streaming)
- Используй CDN для раздачи файлов
- Сжимай изображения
- Используй presigned URLs для S3

4. Обработка ошибок:

- Валидируй до сохранения
- Используй временные файлы
- Удаляй неполные загрузки
- Логируй все ошибки

5. Documentation:

Эндпоинт: POST /api/v1/files/upload
Метод: multipart/form-data
Поля:
  - file (required): бинарный файл, макс 10MB
  - description (optional): текстовое описание
Ответ: {"id": "uuid", "url": "http://..."}

Заключение

Рекомендация: в большинстве случаев используйте multipart/form-data — это стандарт для файлозагрузок, поддерживается везде, и позволяет передавать файлы вместе с метаданными. Для специальных случаев (большие файлы, нестабильная сеть) используйте chunked upload.