Node.js Mongo Grid fs的视频未在Safari浏览器上播放(也在Cordova应用程序上)

Node.js Mongo Grid fs的视频未在Safari浏览器上播放(也在Cordova应用程序上),node.js,mongodb,safari,html5-video,mongoskin,Node.js,Mongodb,Safari,Html5 Video,Mongoskin,我使用Mongodb将视频文件存储为网格文件。今天当我知道Safari浏览器上没有播放视频时,我感到很惊讶。然而,从Gridfs读取的视频在Chrome和Firefox上播放得很好。下面是从网格fs读回视频文件的两种方法。这两种方法都有相同的问题。我认为正确的mime类型正在设置。 方法1: exports.previewFile = function (req, res) { var contentId = new DBModule.BSON.ObjectID(req.params.f

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

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的屏幕供参考。 请帮助

试试这个要点(通过)

它使用字节范围标头

虽然safari不适合我,但它确保设置了正确的hears并提供了正确的内容。它可以缩小你的问题范围

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);
  }
}
编辑

我已经更新了要点。对我来说,它现在可以和Safari一起使用了

这应该能解决你的问题

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);
  }
}
问候 Rolf

试试这个要点

它使用字节范围标头

虽然safari不适合我,但它确保设置了正确的hears并提供了正确的内容。它可以缩小你的问题范围

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);
  }
}
编辑

我已经更新了要点。对我来说,它现在可以和Safari一起使用了

这应该能解决你的问题

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);
  }
}
问候
Rolf

您需要支持字节范围请求。Safari通过指定所需的字节范围,一次只请求部分视频。您的服务器需要处理这些范围请求,并且只响应它想要的视频中的字节范围。如何支持字节范围请求?请分享一些关于这方面的指导。请参阅,并参阅和,以获取有关此主题的更多信息。您需要支持字节范围请求。Safari通过指定所需的字节范围,一次只请求部分视频。您的服务器需要处理这些范围请求,并且只响应它想要的视频中的字节范围。如何支持字节范围请求?请就此分享一些指导。请参阅,并参阅和,以了解有关该主题的更多信息。您可能应该检查以确保
GridFile.length
不小于
start
,如果是,则返回409状态。您还应该
end=Math.min(GridFile.length,end)操作。除此之外,您缺少的唯一(复杂)功能是多字节范围支持。您可能应该检查以确保
GridFile.length
不小于
start
,如果小于,则返回409状态。您还应该
end=Math.min(GridFile.length,end)操作。除此之外,您唯一(复杂)缺少的是多字节范围支持。