Задача состоит в том, чтобы при загрузке данных на сервере срабатывал некоторый триггер, который бы регистрировал сколько данных поступило за единицу времени. Т.е. клиент отправляет бинарные данные через POST. Как только данные (даже если частично) достигают сервера, он считает сколько байт пришло и уведомляет об этом другого клиента (например через вебсокеты).
Как сделать так, чтобы информация о поступлении данных на сервере появлялась в режиме реального времени (или максимально близко к этому)? Вебсокеты для отправки данных не подходят, только http.
Сделал следующим образом. Есть простая отправка данных POST-ом на сервер NodeJS. Я хочу начать получать данные на сервере как только они туда начнут поступать, как можно скорее, не дожидаясь всего тела запроса.
Для этого использую событие 'data' .
https://nodejs.org/uk/docs/guides/anatomy-of-an-ht...
https://nodejs.org/api/stream.html#event-data
Ожидаю, что как только запрос достигнет сервера, данные сразу же появятся в событии 'data'.
Проблема в том, что событие 'data' триггерится с задержкой и чем больше размер отправляемых данных, тем больше задержка. Например, если отправляю 1Мб, то задержки практически не видно, но если отправляю 50Мб, то задержка становится очень существенной (порядка 10секунд). Речь идет о реальном сервере, потому что на локалхосте это не так заметно.
Такое впечатление, что событие 'data' триггерится только после того как данные полностью поступили на сервер.
Не могу разобраться почему так происходит? Ниже простой пример, который наглядно показывает, что данные в 'data' на сервере появляются с задержкой.
Код серверной части.
spoilerconst http = require('http');
var firstByte = null;
var serverLog = {};
var server = http.createServer((request, response) => {
const { headers, method, url } = request;
let body = [];
request.on('error', (err) => {
}).on('data', (chunk) => {
if (!firstByte) {
firstByte = Date.now();
serverLog.backendReceivedFirstData = firstByte;
}
}).on('end', () => {
var end = Date.now();
serverLog.backendReceivedAllData = end;
if (url === '/') {
response.statusCode = 200;
response.setHeader('Content-Type', 'text/html');
response.write('<h1>Hello World</h1>');
} else {
response.statusCode = 200;
response.setHeader('Content-Type', 'application/json');
response.write(JSON.stringify(serverLog));
}
firstByte = null;
serverLog = {};
response.end();
});
var requestReceived = Date.now();
serverLog.backendRequestReceived = requestReceived;
});
server.listen(4000);
Код браузерной части:
spoiler// send 50Mb
var dataToSend = prepareDataBlob(50 * 1024 * 1024);
var start = Date.now();
fetch("http://localhost:4000/upload?a=" + Date.now(), {
body: dataToSend,
method: "post"
}).then(async response => {
const data = await response.json();
console.log(`difference between start and server received a request: ${data.backendRequestReceived - start}`);
console.log(`difference between start and first byte received on server: ${data.backendReceivedFirstData - start}`);
console.log(`difference between start and all data received on server: ${data.backendReceivedAllData - start}`);
});
function prepareDataBlob(fileSize) {
const DEFAULT_UPLOAD_DATA = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
var data = '';
var count = fileSize / DEFAULT_UPLOAD_DATA.length;
for (var j = 0; j < count; j++) data += DEFAULT_UPLOAD_DATA;
var dataBlob = new Blob([data], {
type: 'application/octet-stream'
});
return data;
}