简体   繁体   English

无法在Node.js服务器提供的Safari中播放mp4视频

[英]Can't play mp4 video in Safari served by nodejs server

I'm having a problem loading mp4 video files on Safari being served from my nodejs server. 我在从nodejs服务器提供的Safari上加载mp4视频文件时遇到问题。 The problem does not exist on Chrome. 该问题在Chrome上不存在。

To illustrate the problem, I have a simple html webpage which reads an mp4 file mov_bbb.mp4 served from w3schools. 为了说明这个问题,我有一个简单的HTML网页,该网页读取了w3schools提供的mp4文件mov_bbb.mp4 I then download the same file and serve it from my nodejs server. 然后,我下载相同的文件并从我的nodejs服务器提供它。

vid1 (served from w3schools) loads fine on both Chrome and Safari. vid1 (由w3schools提供)在Chrome和Safari上均可正常加载。

vid2 (served from my nodejs server) load fine on Chrome but not on Safari. vid2 (由我的nodejs服务器提供)可以在Chrome上正常加载,但不能在Safari上加载。

Here's a screenshot of what I see in Chrome: 这是我在Chrome中看到的屏幕截图:

在此处输入图片说明

Here's a screenshot of what I see in Safari: 这是我在Safari中看到的屏幕截图:

在此处输入图片说明

Here is my html: 这是我的html:

<!DOCTYPE html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <video id="vid1" controls preload="auto" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
    <video id="vid2" controls preload="auto" src="http://localhost:8125/mov_bbb.mp4"></video>
  </body>
</html>

Here is my nodejs server: 这是我的nodejs服务器:

var http = require('http');
var fs = require('fs');
var path = require('path');

http.createServer(function (request, response) {
    console.log('request starting...');

    var filePath = '.' + request.url;
    if (filePath == './')
        filePath = './index.html';

    var extname = path.extname(filePath);
    var contentType = 'video/mp4';

    fs.readFile(filePath, function(error, content) {
        if (error) {
            if(error.code == 'ENOENT'){
                fs.readFile('./404.html', function(error, content) {
                    response.writeHead(200, { 'Content-Type': contentType });
                    response.end(content, 'utf-8');
                });
            }
            else {
                response.writeHead(500);
                response.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
                response.end();
            }
        }
        else {
            response.writeHead(200, {
            });
            response.end(content, 'utf-8');
        }
    });

}).listen(8125);
console.log('Server running at http://127.0.0.1:8125/');

Any suggestions would be much appreciated. 任何建议将不胜感激。

Update: 更新:

Revised nodejs code. 修订的nodejs代码。 Still same issue on Safari though: Safari上仍然存在相同的问题:

var http = require('http');
var fs = require('fs');

http.createServer(function (request, response) {
  console.log('request starting...');

  var filePath = '.' + request.url;
  if (filePath == './') {
    var contentType = 'text/html';
    filePath = './index.html';
  } else {
    var contentType = 'video/mp4';
  }

  var rstream = fs.createReadStream(filePath);
  rstream.on('error', function(error) {
    response.writeHead(404);
    response.end();
  });
  rstream.on('open', function () {
    response.writeHead(200, {
      'Content-Type': contentType,
    });
  });
  rstream.pipe(response);
}).listen(8125);
console.log('Server running at http://127.0.0.1:8125/');

Also chrome inspector for http headers: 也是http标头的Chrome检查器:

在此处输入图片说明

First off, don't use readFile() for serving files, it causes unnecessary (potentially high) memory usage because it's loading the entire file into memory. 首先,请勿使用readFile()来提供文件,因为它将整个文件加载到内存中会导致不必要的内存使用(可能很高)。 Use fs.createReadStream() and pipe it to the response instead. 使用fs.createReadStream()并将其通过管道传递到response

Secondly and most importantly, a Content-Type is not being sent in the success case. 其次,也是最重要的是,成功情况下不会发送Content-Type Also, the Content-Type is wrong in the error case because text/html data is being sent in the response, not video/mp4 data. 同样,在错误情况下, Content-Type是错误的,因为在响应中发送的是文本/ html数据,而不是video / mp4数据。

Additionally, arbitrary paths should not be passed to filesystem calls because someone could pass a malicious path (including relative paths to get to the filesystem root) and read sensitive information from your filesystem (eg private keys, passwords, etc.). 另外,不应将任意路径传递给文件系统调用,因为有人可以传递恶意路径(包括到达文件系统根目录的相对路径)并从文件系统中读取敏感信息(例如私钥,密码等)。

Lastly, if you're going to write a Buffer to a response, you don't need to specify an encoding (eg 'utf-8' ) because the data is already in Buffer form. 最后,如果您打算将Buffer写入响应,则无需指定编码(例如'utf-8' ),因为数据已经是Buffer形式。

The issue with the video playback has to do with handling the Content-Range range header which must be implemented on the server. 视频播放的问题与处理必须在服务器上实现的Content-Range范围标头有关。 Chrome and Safari send different request headers. Chrome和Safari发送不同的请求标头。 In my case Chrome sends a single request with range: 就我而言,Chrome发送了一个范围为一个的请求:

bytes=0-

Whereas Safari sends multiple requests: Safari发送多个请求:

bytes=0-1
bytes=0-1013150
bytes=197534-1013150

For more information see this thread and for specific code that worked for me see this answer . 有关更多信息,请参见此线程 ,对于对我有用的特定代码,请参见此答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM