视频:修 media.php 的 304/Range 冲突,HEVC 解不了时给明确提示 (#52)
304 判定没有排除 Range 请求:视频第二次打开时浏览器同时发 Range + If-None-Match,命中 304 拿到空响应 ⇒ 黑屏。 改成 $hasRange 为真时跳过 304。顺手补 Last-Modified(部分浏览器需要它才允许 seek)。 另查明用户的视频是 H.265/HEVC,Chrome/Firefox 无法解码 —— 浏览器端无解, 检测到解码失败时显示提示卡片 + 下载入口,不再给一块黑屏。
This commit is contained in:
@@ -217,8 +217,25 @@ $etag = '"' . md5($key . '|' . $size . '|' . $mime) . '"';
|
||||
v47 的缓存回写(见第 3 步)让第二次开始命中的是**本地文件**,
|
||||
所以这里"取回来再判 304"的代价已经降到本地读盘级别,够用了。
|
||||
(真要连本地读都省掉,得把 ETag 单独持久化 —— 那是下一步的事。) */
|
||||
|
||||
/* 🔴🔴 2026-11-05 修(用户:「网页端的视频…点开之后是黑的,没办法播放」):
|
||||
**带 Range 的请求绝不能回 304**。
|
||||
|
||||
原来的顺序是"先判 304,再处理 Range"。视频第一次播完后浏览器缓存了 ETag,
|
||||
拖动进度条 / 第二次打开时会同时发:
|
||||
|
||||
Range: bytes=1048576-
|
||||
If-None-Match: "abc123"
|
||||
|
||||
⇒ 命中 304(304 **没有响应体**)⇒ `<video>` 拿不到数据 ⇒ **黑屏**。
|
||||
这就是"有时候能播、有时候黑"的根因:取决于浏览器有没有带 ETag。
|
||||
|
||||
RFC 7233 也明确:304 不能替代对 Range 的响应。
|
||||
⇒ 有 Range 就跳过 304,直接走第 6 步。 */
|
||||
$hasRange = trim((string)($_SERVER['HTTP_RANGE'] ?? '')) !== '';
|
||||
|
||||
$inm = trim((string)($_SERVER['HTTP_IF_NONE_MATCH'] ?? ''));
|
||||
if ($inm !== '' && $inm === $etag) {
|
||||
if (!$hasRange && $inm !== '' && $inm === $etag) {
|
||||
http_response_code(304);
|
||||
header('ETag: ' . $etag);
|
||||
header('Cache-Control: private, max-age=604800');
|
||||
@@ -261,6 +278,9 @@ if ($isRange) {
|
||||
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
|
||||
}
|
||||
header('Accept-Ranges: bytes');
|
||||
/* 2026-11-05:补 Last-Modified —— 部分浏览器/Safari 需要它才允许 seek,
|
||||
缺了会对某些 mp4 直接拒绝播放(表现为黑屏 + 无报错)。 */
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
|
||||
$filename = basename($key);
|
||||
$disp = !empty($_GET['dl']) ? 'attachment' : 'inline';
|
||||
header('Content-Disposition: ' . $disp . '; filename="' . rawurlencode($filename) . '"');
|
||||
|
||||
Reference in New Issue
Block a user