我有一个 Azure Web 应用程序(托管 React 应用程序),其中 ios/safari 用户无法加载我的 .mp4 文件。其他浏览器没有问题。在 chrome 上,文件返回 200 OK,媒体类型为 video/mp4 。它是一个 Linux 容器,它使用(根据文档)提供文件:
我读到 ios/safari 希望为这些类型的大文件返回 206,但我不知道如何设置。
我在 /site/wwwroot 中有一个 web.config (尝试了其他位置但结果相同),但它似乎没有产生任何影响。
“Safari 中流式传输的怪异案例”,来自 Tomer Steinfeld,解释了从 Safari 客户端进行流式传输时的“规则”。
服务器必须:
支持206部分内容,如Ashley Davis的“Safari中的流媒体视频:为什么这么难?”所示:状态代码根据这是对完整文件的请求还是对单个文件的请求而有所不同文件一部分的范围请求。如果是范围请求,状态码将为206(针对部分内容);否则,我们使用常规的旧成功状态代码 200。
返回正确的
Content-Type
标头和类型 attribute
(显然,Safari 会检查三件事以确定视频资源的类型。类型 attribute
必须与 Content-Type
标头和 URL 匹配必须以匹配的扩展名结尾。),
向视频添加匹配的文件扩展名
src
URL。
您的节点应用程序,由 PM2 提供服务,可能如下所示:
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}`);
});
进行以下修改:
/video/:file.mp4
,其中 :file
是不带扩展名的视频文件的名称。这将确保 URL 以 .mp4
扩展名结尾,满足 Safari 的要求。Content-Type
标头设置为 'video/mp4'
,与 MP4 视频的文件扩展名和 MIME 类型匹配。该代码应符合 Safari 对流视频内容的要求,并且也应适用于其他浏览器。确保视频位于服务器目录中名为“
videos
”的目录中。当然,您可以根据需要修改路径以匹配您的实际文件位置。