Как передавать большие файлы через WebSocket

Короткий ответ: объемные файлы через WebSocket можно передавать чанками, но это не всегда лучший выбор. Если задача — просто загрузить файл на сервер, чаще правильнее использовать обычный HTTP upload, object storage или multipart-загрузку, а через WebSocket отправлять только прогресс, статус обработки и уведомления. WebSocket имеет смысл, если файл является частью постоянного двустороннего сценария

Если все-таки нужно передавать файл через WebSocket, делайте так:

  • режьте файл на куски;
  • отправляйте метаданные;
  • ждите подтверждения или контролируйте буфер;
  • собирайте куски на сервере;
  • ограничивайте размер и тип файла.

Клиент: отправка файла чанками

async function sendFile(socket, file) {
  const chunkSize = 64 * 1024;
  const fileId = crypto.randomUUID();
  const totalChunks = Math.ceil(file.size / chunkSize);

  socket.send(JSON.stringify({
    type: "file_start",
    fileId,
    name: file.name,
    size: file.size,
    totalChunks,
  }));

  for (let index = 0; index < totalChunks; index++) {
    const start = index * chunkSize;
    const chunk = file.slice(start, start + chunkSize);
    const buffer = await chunk.arrayBuffer();

    socket.send(JSON.stringify({
      type: "file_chunk_meta",
      fileId,
      index,
    }));

    socket.send(buffer);
  }

  socket.send(JSON.stringify({
    type: "file_end",
    fileId,
  }));
}

Здесь метаданные идут JSON-сообщениями, а сам кусок файла — бинарным сообщением

Контроль bufferedAmount

Если отправлять большой файл слишком быстро, данные начнут копиться в буфере браузера:

console.log(socket.bufferedAmount);

Простая пауза:

function waitForBuffer(socket, limit = 1024 * 1024) {
  return new Promise((resolve) => {
    const timer = setInterval(() => {
      if (socket.bufferedAmount < limit) {
        clearInterval(timer);
        resolve();
      }
    }, 50);
  });
}

В цикле:

await waitForBuffer(socket);
socket.send(buffer);

Это не полноценный надежный протокол, но уже лучше, чем бездумно отправить гигабайт в открытый сокет

Серверная идея

На сервере нужно хранить состояние загрузки:

const uploads = new Map();
let currentChunk = null;

socket.on("message", (message, isBinary) => {
  if (!isBinary) {
    const data = JSON.parse(message.toString());

    if (data.type === "file_start") {
      uploads.set(data.fileId, {
        name: data.name,
        chunks: [],
      });
    }

    if (data.type === "file_chunk_meta") {
      currentChunk = data;
    }

    if (data.type === "file_end") {
      const upload = uploads.get(data.fileId);
      const file = Buffer.concat(upload.chunks);
      console.log("Файл собран:", upload.name, file.length);
    }

    return;
  }

  if (currentChunk) {
    const upload = uploads.get(currentChunk.fileId);
    upload.chunks[currentChunk.index] = Buffer.from(message);
  }
});

В production-коде нужно писать куски на диск или в storage, а не держать большой файл целиком в памяти

Когда лучше не использовать WebSocket

Не используйте WebSocket для больших файлов, если достаточно обычной формы загрузки. HTTP upload проще масштабировать, логировать, ограничивать, возобновлять и отдавать через CDN/storage

Хорошая схема:

Файл -> HTTP/S3 upload
Статус обработки -> WebSocket

Например, пользователь загружает видео по HTTP, а WebSocket показывает: “загружено”, “конвертируется”, “готово”

Частые ошибки

Первая ошибка — отправить файл одним сообщением. Для больших файлов это может убить память, буфер и соединение

Вторая ошибка — не проверять размер файла. Установите лимит на клиенте и сервере

Третья ошибка — смешать метаданные и бинарные данные без порядка. Сервер должен понимать, к какому fileId относится следующий chunk

Четвертая ошибка — не обрабатывать обрыв соединения. Если сокет закрылся на 80%, нужно удалить временные куски или дать возможность продолжить загрузку

Самопроверка

Возьмите файл 2-5 МБ, отправьте его чанками и залогируйте количество полученных частей. Затем намеренно разорвите соединение в середине и проверьте, что сервер не считает файл готовым

Что почитать дальше по WebSocket

Если нужен общий маршрут по теме, откройте рубрику WebSocket. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x