Короткий ответ: объемные файлы через 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. Для соседних задач пригодятся эти разборы:
- Django: как подружить Celery с WebSocket
- Django: как сохранить биржевые данные, полученные по WebSocket
- FastAPI WebSocket: уведомления в браузер
- Fedora 43: как установить WebSocket сервер



