В настоящее время я ожидаю некоторых проблем с бэкендом, которым я управляю. Он использует GridFS для хранения и получения видео в MongoDB. Теперь это работает в течение полугода или около того, но вдруг это уже не так. Это код до сих пор
const getByFilename = async (req: Request, res: Response, next: NextFunction) => {
try {
let filename = req.params.Filename
let media = await MediaService.getByFilename(filename);
if (req.headers.range) {
let parts = req.headers.range.replace(/bytes=/, '').split('-');
let partialStart = parts[0];
let partialEnd = parts[1];
let start = parseInt(partialStart, 10);
let end = partialEnd ? parseInt(partialEnd, 10) : media.length - 1;
let chunkSize = (end - start) + 1;
res.writeHead(206, {
'Accept-Ranges': 'bytes',
'Content-Length': chunkSize,
'Content-Range': `bytes ${start}-${end}/${media.length}`,
'Content-Type': media.contentType,
});
let readstream: ReadStream = grid.gfs.createReadStream({
filename,
range: {
startPos: start,
endPos: end
}
}).pipe(res);
readstream.on('data', buff => {
start += buff.length;
if (start >= end) {
return res.end();
} else {
res.write(buff);
}
});
readstream.on('err', err => {
handleError(err, res);
});
readstream.pipe(res);
} else {
res.header('Content-Length', media.length);
res.header('Content-Type', media.contentType);
res.header('Content-Metadata', JSON.stringify(media.metadata))
grid.gfs.createReadStream({
filename
}).pipe(res);
}
} catch (err) {
handleError(err, res);
}
}
Теперь первая ошибка, которую я получаю, заключается в том, что заголовки HTTP пытаются установить после их отправки. Это кажется довольно очевидным (по крайней мере, я предполагаю), потому что код сначала устанавливает переменную readstream путем непосредственного конвейерного подключения, а затем снова конвейерное чтение readstream в конце блока try. Хотя это кажется очевидным, я не могу обернуть голову, как это работало в прошлом (и до сих пор работает в контейнере докера моего продукта). Последний раз gridfs-stream был опубликован 4 года назад, поэтому изменение версии также не является причиной проблемы.
Теперь, если я изменю код, чтобы сначала создать поток чтения (без непосредственного его передачи)
let readstream: ReadStream = grid.gfs.createReadStream({
filename,
range: {
startPos: start,
endPos: end
}
});
затем выполняю обработку событий, как до и после того канала, который читает поток
readstream.pipe(res)
, что более логично, похоже, что браузер просто получит первый фрагмент видео.
Есть идеи? Я как бы потерялся здесь
Насколько я понимаю, как это должно работать
- Запрос приходит без диапазона в заголовках. и readstream изначально создается и отправляется
- Запрос приходит с заголовком диапазона. Приложение будет продолжать запись в буфер, устанавливая заголовок диапазона содержимого в ответе.
- Как только запрошенный диапазон достигнет границы запрошенной длины контента, будет отправлен res.end () и ответ будет завершен.
Однако при отладке я замечаю следующие затруднения.
- работает как надо
- Я начинаю нажимать на часть, где данные записываются в буфер. но не так много раз, как следовало бы.
- Иногда срабатывает функция res.end (), иногда нет. Если это происходит, хотя это происходит, и после этого происходит больше шагов 2