node.js - 来自 Mongodb Gridfs 的视频无法在 Safari 浏览器上播放(也在 Cordova 应用程序上)

标签 node.js mongodb safari html5-video mongoskin

我正在使用 Mongodb 将视频文件存储为网格文件系统。今天,当我得知视频无法在 Safari 浏览器上播放时,我感到很惊讶。然而,从 Gridfs 读取的视频在 Chrome 和 Firefox 上播放得很好。以下是从 Grid fs 读回视频文件的两种方法。两种方法都有同样的问题。我确实设置了正确的 mime 类型。 方法一:

exports.previewFile = function (req, res) {
    var contentId = new DBModule.BSON.ObjectID(req.params.fileid);
    log.debug('Calling previewFile inside FileUploadService for content id ' + contentId);
    //Read metadata details from fs.files
    var query = {_id: contentId};
    documentOperationModule.getDocumentByQuery(query, constants.FS_FILES_COLLECTION, function (err, files) {
        if (!Utilities.isEmptyList(files)) {
            var fileObj = files[0];
            var gridStore = DBModule.db.gridStore(contentId, 'r');
            gridStore.open(function (err, gridStore) {
                var stream = gridStore.stream(true);
                if (!Utilities.isEmptyObject(fileObj.metadata)) {
                    res.setHeader('Content-Type', fileObj.metadata.contentType);
                }
                stream.on("data", function (chunk) {
                    log.debug("Chunk of file data");

                    res.write(chunk);
                });

                stream.on("end", function () {
                    log.debug("EOF of file");
                    res.end();
                });

                stream.on("close", function () {
                    log.debug("Finished reading the file");
                });
            });          
        } else {
            log.error({err: err}, 'Failed to read the content for id ' + contentId);
            res.status(constants.HTTP_CODE_INTERNAL_SERVER_ERROR);
            res.json({error: contentId + " not found"});
        }

    });
};

方法 2:

exports.previewFile = function (req, res) {
    var contentId = new DBModule.BSON.ObjectID(req.params.fileid);
    log.debug('Calling previewFile inside FileUploadService for content id ' + contentId);
    //Read metadata details from fs.files
    var query = {_id: contentId};
    documentOperationModule.getDocumentByQuery(query, constants.FS_FILES_COLLECTION, function (err, files) {
        if (!Utilities.isEmptyList(files)) {
            var fileObj = files[0];
            var gridStore = DBModule.db.gridStore(contentId, 'r');        

             gridStore.read(function (err, data) {
             if (!err) {
             if (!Utilities.isEmptyObject(fileObj.metadata)) {
             res.setHeader('Content-Type', fileObj.metadata.contentType);
             }
             res.end(data);
             } else {
             log.error({err: err}, 'Failed to read the content for id ' + contentId);
             res.status(constants.HTTP_CODE_INTERNAL_SERVER_ERROR);
             res.json({error: err});
             }                
             }); 
        } else {
            log.error({err: err}, 'Failed to read the content for id ' + contentId);
            res.status(constants.HTTP_CODE_INTERNAL_SERVER_ERROR);
            res.json({error: contentId + " not found"});
        }

    });
};

以下是 Safari 的屏幕供引用。 enter image description here 请帮忙

最佳答案

试试这个 GIST(作者 https://gist.github.com/psi-4ward)

它使用字节范围 header

https://gist.github.com/psi-4ward/7099001

虽然它不适用于 safari,但它可以确保设置正确的聆听并传递正确的内容。它可以缩小您的问题范围

编辑

我已经更新了 GIST。现在我在 Safari 上工作得很好

https://gist.github.com/derMani/218bd18cc926d85a57a1

这应该可以解决您的问题

function StreamGridFile(req, res, GridFile) {
  if(req.headers['range']) {
    // Range request, partialle stream the file
    console.log('Range Reuqest');
    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) : GridFile.length -1;
    var chunksize = (end-start)+1;

    res.writeHead(206, {
      'Content-disposition': 'filename=xyz',
      'Accept-Ranges': 'bytes',
      'Content-Type': GridFile.contentType,
      'Content-Range': 'bytes ' + start + '-' + end + '/' + GridFile.length,
      'Content-Length': chunksize
    });

    // Set filepointer
    GridFile.seek(start, function() {
      // get GridFile stream
      var stream = GridFile.stream(true);

      // write to response
      stream.on('data', function(buff) {
        // count data to abort streaming if range-end is reached
        // perhaps theres a better way?
        if(start >= end) {
          // enough data send, abort
          GridFile.close();
          res.end();
        } else {
          res.write(buff);
        }
      });
    });

  } else {

    // stream back whole file
    console.log('No Range Request');
    res.header('Content-Type', GridFile.contentType);
    res.header('Content-Length', GridFile.length);
    var stream = GridFile.stream(true);
    stream.pipe(res);
  }
}

问候 罗尔夫

关于node.js - 来自 Mongodb Gridfs 的视频无法在 Safari 浏览器上播放(也在 Cordova 应用程序上),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31154100/

相关文章:

javascript - 使用嵌入或 iframe 在模态中使用 Angular 4 上传前预览

mysql - 使用 Sequelize 排除空关联数组

javascript - 按国家过滤并使用 mongoose 自由文本搜索 mongodb

node.js - 无法在 Postman 中发送 POST 请求 "/api/user/cart/addtocart%0A"

java - 可以从 Java 或 JavaFx 使用 mongorestore 和 mongodump 命令吗?

javascript - Safari- show() 和 css ('display' ,'block' ) 不起作用

Node.js + SQLite 异步事务

javascript - 如果 statusCode 不是 200,http 调用会返回什么类型的错误对象?

css - Safari 关键帧不起作用

javascript - 通过 Safari Extension 获取选中的文本