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

耗尽温柔 提交于 2021-02-10 14:16:27

问题


I'm having a problem loading mp4 video files on Safari being served from my nodejs server. The problem does not exist on Chrome.

To illustrate the problem, I have a simple html webpage which reads an mp4 file mov_bbb.mp4 served from w3schools. I then download the same file and serve it from my nodejs server.

vid1 (served from w3schools) loads fine on both Chrome and Safari.

vid2 (served from my nodejs server) load fine on Chrome but not on Safari.

Here's a screenshot of what I see in Chrome:

Here's a screenshot of what I see in Safari:

Here is my 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:

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. Still same issue on Safari though:

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:


回答1:


The issue with the video playback has to do with handling the Content-Range range header which must be implemented on the server. Chrome and Safari send different request headers. In my case Chrome sends a single request with range:

bytes=0-

Whereas Safari sends multiple requests:

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.




回答2:


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. Use fs.createReadStream() and pipe it to the response instead.

Secondly and most importantly, a Content-Type is not being sent in the success case. Also, the Content-Type is wrong in the error case because text/html data is being sent in the response, not video/mp4 data.

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 (e.g. private keys, passwords, etc.).

Lastly, if you're going to write a Buffer to a response, you don't need to specify an encoding (e.g. 'utf-8') because the data is already in Buffer form.



来源:https://stackoverflow.com/questions/42846947/cant-play-mp4-video-in-safari-served-by-nodejs-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!