无法使用 GridFS 从 MongoDB 流式传输视频



我尝试从MongoDB流式传输视频已经有一段时间了。阅读了大量的api DOC和示例,但无法使其正常工作

这是我的前端视频处理器:

import { useState, useEffect } from "react";
import ReactPlayer from "react-player";
const CatVideos = () => {
const [videoList, setvideoList] = useState(null);
useEffect(() => {
const getVideos=async ()=> {
const response = await fetch('http://localhost:8000/cat-videos/videos');
const data = await response.json();
setvideoList(data);
console.log(data);
}
getVideos();
}, [])

return (
<div>
<h1>Cat videos</h1>
{videoList!=null && videoList.map((video)=>{
return <ReactPlayer key={video._id} url={'http://localhost:8000/cat-videos/videos/'+video._id}/>
})}
</div>
);
};
export default CatVideos;

后端流功能:

exports.getVideoStream = (req, res, next) => {
var id = req.params.id;
let gfs = Grid(conn.db, mongoose.mongo);
gfs.collection("videos");
gfs.files
.findOne({
_id: mongoose.Types.ObjectId(id),
})
.then((result) => {
const file = result;
if (!file) {
return res.status(404).send({
err: "Unavailable.",
});
}
if (req.headers["range"]) {
var parts = req.headers["range"].replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : file.length - 1;
var chunksize = end - start + 1;
res.header("Accept-Ranges", "bytes");
res.header("Content-Length", chunksize);

res.header(
"Content-Range",
"bytes " + start + "-" + end + "/" + result.length
);
console.log(result.contentType)
res.header("Content-Type", result.contentType);
gfs.createReadStream({
_id: result._id,
range: {
startPos: start,
endPos: end,
},
}).readStream.pipe(res);

} else {
console.log("#################before####################");
res.header("Content-Length", result.length);
res.header("Content-Type", result.contentType);
console.log(result._id);
gfs
.createReadStream({
_id: result._id,
})
.pipe(res);
}
})
.catch((err) => {
res.json(err);
});
};

我确实从这个函数得到了响应;内容类型";保持不变。

HTTP/1.1 206 Partial Content
X-Powered-By: Express
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Date: Thu, 23 Dec 2021 19:38:25 GMT
Content-Type: application/json; charset=utf-8
ETag: W/"2-vyGp6PvFo4RvsFtPoIWeCReyIC8"
Content-Range: bytes 0-1/2
Content-Length: 2

后端依赖关系:

"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.1",
"cors": "^2.8.5",
"ejs": "^3.1.6",
"express": "^4.17.2",
"gridfs-stream": "^1.1.1",
"method-override": "^3.0.0",
"mongodb": "^4.2.2",
"mongoose": "^6.1.2",
"multer": "^1.4.4",
"multer-gridfs-storage": "^5.0.2"
}

前端依赖关系:

"axios": "^0.24.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-player": "^2.9.0",
"react-router-dom": "^6.2.1",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.2"

我设法解决了这个问题。请注意,GridFSBucket有一个默认的bucket名称。浏览API文档,它说它附加了存储桶名称";。文件";。我的问题是,我没有定义它,下载流中的起始端没有正确定义,导致了一个错误。

你也可以用它来流式传输图像,视频只是改变前端的内容类型。相当普通的流。

exports.getVideoStream = (req, res, next) => {
mongodb.MongoClient.connect(url, function (error, client) {
if (error) {
res.status(500).json(error);
return;
}
// Check for range headers to find our start time
const range = req.headers.range;
if (!range) {
res.status(400).send("Requires Range header");
}
const db = client.db('videos');
// GridFS Collection
console.log(req.params.id);
db.collection('videos.files').findOne({_id:mongoose.Types.ObjectId(req.params.id)}, (err, video) => {
if (!video) {
res.status(404).send("No video uploaded!");
return;
}
// Create response headers
const videoSize = video.length;
const start = Number(range.replace(/D/g, ""));
const end = videoSize - 1;
const contentLength = end - start + 1;
const headers = {
"Content-Range": `bytes ${start}-${end}/${videoSize}`,
"Accept-Ranges": "bytes",
"Content-Length": contentLength,
"Content-Type": "video/mp4",
};
// HTTP Status 206 for Partial Content
res.writeHead(206, headers);
// Get the bucket and download stream from GridFS
const bucket = new mongodb.GridFSBucket(db,{bucketName:"videos"});

const downloadStream = bucket.openDownloadStream(video._id, {
start:start,
end:end
});
// Finally pipe video to response
console.log(streamCounter," start ",start," end ",end)
streamCounter++;
downloadStream.pipe(res);
});
});

};

最新更新