2

I have a Azure web app (hosting a react app) where ios/safari users can not load my .mp4 files. Other browser have no problem. On chrome the file is returned 200 OK, as media type video/mp4 . It is a linux container and it servse the files using(as per documentation): Node js 16
Startup Command:
pm2 serve /home/site/wwwroot --no-daemon

I have read that ios/safari want 206 returned for these types of big files but I have no idea on how to set that up.

I have a web.config in /site/wwwroot (tried other locations but same result) but it does not seem to make any impact. enter image description here

Todilo
  • 1,256
  • 3
  • 19
  • 38

2 Answers2

1

My Conclusions After Investigation:

you need custom configuration for 206 in application server.

also your best bet will be nginx (success case), its very smart for such edge cases, and is recommended way to offload your static content streaming rather than node (or any application server) handle serving large content.

just a reminder : dont waste your time fighting with existing solution or bugs

  • just ask users to upgrade, they will happily do it in most cases.
  • switch to different provider or use hybrid solution, many a times for cost or compatibility reasons my solutions have 2 or more clouds. its going good as far as i can say.
Adriaan
  • 17,741
  • 7
  • 42
  • 75
nikhil swami
  • 2,360
  • 5
  • 15
0

"The Weird Case of Streaming in Safari" from Tomer Steinfeld explains the "rules" when it comes to streaming from a Safari client.

The server must:

  • Support 206 partial content, as shown in "Streaming video in Safari: Why is it so difficult?" from Ashley Davis: The status code varies depending on whether this is a request for the full file or a range request for a portion of the file. If it is a range request, the status code will be 206 (for partial content); otherwise, we use the regular old success status code of 200.

  • Return the correct Content-Type header and type attribute (Apparently, Safari checks three things in order to determine the type of resource to be a video. The type attribute must match the Content-Type header, and the URL must end with a matching extension.),

  • Add a matching file extension to the video src URL.

Your node app, served by PM2, could look like:

const express = require('express');
const fs = require('fs');
const path = require('path');

const app = express();

app.get('/video/:file.mp4', (req, res) => {
  const filePath = path.join(__dirname, 'videos', req.params.file + '.mp4');
  const stat = fs.statSync(filePath);
  const fileSize = stat.size;
  const range = req.headers.range;

  if (range) {
    const parts = range.replace(/bytes=/, "").split("-");
    const start = parseInt(parts[0], 10);
    const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

    const chunksize = (end - start) + 1;
    const file = fs.createReadStream(filePath, { start, end });
    const head = {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4'
    };

    res.writeHead(206, head);
    file.pipe(res);
  } else {
    const head = {
      'Content-Length': fileSize,
      'Content-Type': 'video/mp4'
    };
    res.writeHead(200, head);
    fs.createReadStream(filePath).pipe(res);
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

With the following modifications:

  • The URL pattern has been changed to /video/:file.mp4, where :file is the name of the video file without the extension. That would make sure that the URL ends with the .mp4 extension, satisfying Safari's requirement.
  • The Content-Type header is set to 'video/mp4', matching the file extension and MIME type for MP4 videos.
  • The server responds to Range header requests with a 206 status code, providing the necessary support for partial content.

That code should comply with Safari's requirements for streaming video content, and it should work for other browsers as well. Make sure that the videos are located in a directory named 'videos' within your server's directory. You can, of course, modify the path as needed to match your actual file locations.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • so I should create my own custom node app? There is no way to configure it in azure? – Todilo Aug 25 '23 at 12:05
  • @Todilo Azure directly, I don't think so. It is better to use an app where you can control everything. – VonC Aug 25 '23 at 12:28