gridfs-流视频文件不再起作用。但是为什么以前能起作用

时间:2019-06-18 06:53:27

标签: node.js mongodb typescript streaming gridfs

我目前正在管理的后端存在一些问题。它使用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,然后在try块的末尾再次通过管道传送readstream。尽管这似乎很明显,但我无法确定过去的工作方式(仍然在我的产品的Docker容器中工作)。 gridfs-stream也于4年前发布,因此版本更改也不是问题的原因。

现在,如果我修改代码,则首先创建readstream(无需直接管道传递)

let readstream: ReadStream = grid.gfs.createReadStream({
  filename,
  range: {
    startPos: start,
    endPos: end
  }
});

然后像读取流的管道之前和之后一样进行事件处理

readstream.pipe(res)

这更有意义,似乎浏览器将只接收视频的第一部分。

有什么想法吗?我有点迷路了

据我了解,这是应该如何工作的

  1. 请求传入的标头中没有范围。并开始创建并发送readstream
  2. 请求带有一个范围标头。应用程序将继续写入缓冲区,以设置响应中的内容范围标头。
  3. 一旦请求的范围达到请求的内容长度的边界,就会发送res.end()并完成响应。

但是在调试时,我注意到以下行为。

  1. 工作正常
  2. 我开始触及将数据写入缓冲区的部分。但没有我应有的次数。
  3. 有时res.end()有时不会触发。如果尽管发生这种情况却触发了它,然后又发生了第二步

0 个答案:

没有答案