guoyu/视频异常处理逻辑.md

396 lines
9.4 KiB
Markdown
Raw Normal View History

2025-12-11 23:28:07 +08:00
# 视频异常处理逻辑总结
## 📊 **整体流程**
```
视频加载 → URL测试 → 元数据加载 → 黑屏检测 → 播放 → 错误处理
```
---
## 1⃣ **视频URL测试testVideoUrl**
### **触发时机:**
- 加载视频课件时(`loadCourseware`
### **处理逻辑:**
```javascript
async testVideoUrl(url) {
// 使用HEAD请求测试文件是否存在不下载文件内容
const res = await uni.request({
url: url,
method: 'HEAD',
timeout: 5000
})
if (res.statusCode === 200) {
✅ 视频文件可访问
- 记录Content-Type
- 记录Content-Length
} else if (res.statusCode === 404) {
❌ 视频文件不存在(404)
- 检查数据库filePath是否正确
} else if (res.statusCode === 403) {
❌ 没有权限访问(403)
} else {
⚠️ 其他响应码
}
}
```
### **作用:**
- ✅ 提前检测视频是否可访问
- ✅ 输出详细日志,便于调试
- ⚠️ **只是日志输出,不会阻止播放**
---
## 2⃣ **黑屏检测与自动修复onVideoLoadedMetadata**
### **触发时机:**
- 视频元数据加载完成时
### **检测逻辑:**
```javascript
if (e.detail.width === 0 || e.detail.height === 0) {
⚠️ 检测到视频尺寸异常(黑屏)
if (videoRetryCount < 3) {
// 自动重试修复
videoRetryCount++
// 强制重新加载视频
this.videoId = 'course-video-' + Date.now() // 重新生成videoId
this.videoUrl = ''
await this.$nextTick()
this.videoUrl = currentUrl
this.initialTime = currentInitialTime
✅ 尝试修复黑屏最多3次
} else {
❌ 已达到最大重试次数,放弃修复
显示提示:'视频加载异常,请退出重试'
}
} else {
✅ 视频尺寸正常,重置重试计数器
videoRetryCount = 0
}
```
### **修复机制:**
1. **检测**宽度或高度为0 → 黑屏
2. **重试**最多3次
3. **方法**重新生成videoId强制组件重建
4. **失败**:显示提示,要求用户退出重试
---
## 3⃣ **播放错误处理onVideoError**
### **触发时机:**
- 视频播放过程中发生错误
### **错误分类与处理:**
#### **A. 根据错误码判断**
```javascript
if (e.detail?.errCode === -1) {
❌ 视频文件不存在或无法访问
} else if (e.detail?.errCode === -2) {
❌ 视频格式不支持
} else if (errMsg.includes('404')) {
❌ 视频文件未找到(404)
} else if (errMsg.includes('403')) {
❌ 没有权限访问视频文件(403)
} else if (errMsg.includes('timeout')) {
❌ 视频加载超时,请检查网络
}
```
#### **B. 自动尝试URL编码切换**
```javascript
// 构建原始URL未编码
const originalUrl = config.FILE_BASE_URL + filePath
// 如果当前URL是编码的尝试未编码版本
if (this.videoUrl !== originalUrl) {
console.log('尝试切换到未编码的URL')
this.videoUrl = originalUrl
// 等待500ms后重新尝试播放
setTimeout(() => {
const videoContext = uni.createVideoContext('course-video')
videoContext.play()
videoContext.pause()
}, 500)
} else {
// 已经尝试过未编码版本,显示错误提示
显示Modal
- 标题:'视频播放失败'
- 内容:错误信息 + 服务器地址 + 文件路径
}
```
#### **C. 显示详细错误信息**
```javascript
uni.showModal({
title: '视频播放失败',
content: `
${errorMsg}
请检查:
1. 服务器是否运行
2. 视频文件是否存在
3. 网络连接是否正常
服务器: ${config.FILE_BASE_URL}
路径: ${courseware.filePath}
`,
showCancel: false,
confirmText: '知道了'
})
```
---
## 4⃣ **视频加载失败的完整处理流程**
```mermaid
graph TD
A[开始加载视频] --> B{URL测试}
B -->|200 OK| C[加载视频]
B -->|404/403/其他| D[输出日志,继续尝试加载]
C --> E{元数据加载}
E -->|成功| F{尺寸检测}
F -->|正常| G[开始播放]
F -->|黑屏| H{重试次数<3?}
H -->|是| I[重新加载视频]
I --> C
H -->|否| J[提示用户:请退出重试]
E -->|失败| K[触发onVideoError]
G --> L{播放过程}
L -->|正常| M[播放完成]
L -->|错误| K
K --> N{URL编码尝试}
N -->|未尝试| O[切换到未编码URL]
O --> C
N -->|已尝试| P[显示错误提示Modal]
```
---
## 5⃣ **不能播放的视频如何处理?**
### **A. 自动处理(无需用户干预)**
#### **1. 黑屏问题**
-**自动重试3次**
-**每次间隔300ms**
-**成功后重置计数器**
-**3次失败后提示用户**
#### **2. URL编码问题**
-**自动尝试未编码版本**
-**间隔500ms后重试**
-**失败后显示Modal**
---
### **B. 需要用户干预**
#### **1. 文件不存在404**
```
结果显示Modal
提示:视频文件未找到(404)
服务器: http://xxx
路径: /profile/upload/xxx.mp4
建议:
- 检查服务器是否运行
- 检查视频文件是否存在
- 检查filePath是否正确
```
#### **2. 权限问题403**
```
结果显示Modal
提示:没有权限访问视频文件(403)
建议:
- 检查服务器权限配置
- 检查防火墙设置
```
#### **3. 网络超时**
```
结果显示Modal
提示:视频加载超时,请检查网络
建议:
- 检查网络连接
- 检查服务器响应速度
```
#### **4. 格式不支持(-2**
```
结果显示Modal
提示:视频格式不支持
建议:
- 转换视频格式为MP4
- 确保编码为H.264
```
---
### **C. 不影响学习进度**
#### **关键逻辑:**
```javascript
// 即使视频无法播放,图片/PDF仍然可以正常学习
// 进度计算:已完成课件数 / 总课件数
if ("video".equals(cw.getType())) {
if (detail != null && detail.getVideoPosition() != null) {
// 有观看记录才计入完成
if (videoPosition >= duration * 0.8) {
completedCount++
}
}
} else {
// 图片/PDF查看过视为完成
if (detail != null) {
completedCount++ // ✅ 不影响
}
}
```
#### **示例:**
```
课程有5个视频 + 3个图片
情况1所有视频都能播放
- 看完3个视频 + 3个图片 → 进度 = 6/8 = 75%
情况2有2个视频无法播放
- 看完3个视频 + 3个图片 → 进度 = 6/8 = 75%
- 无法播放的2个视频不计入除非有观看记录
情况3所有视频都无法播放
- 看完3个图片 → 进度 = 3/8 = 37.5%
- 用户仍可学习图片课件
```
---
## 6⃣ **日志输出(便于调试)**
### **加载阶段:**
```
[课程学习] 📦 加载课件数据: {...}
[课程学习] 课件ID: 893
[课程学习] 课件类型: video
[课程学习] 🔗 URL构建信息:
- FILE_BASE_URL: http://localhost:8080
- 原始filePath: /profile/upload/xxx.mp4
- 完整URL: http://localhost:8080/profile/upload/xxx.mp4
[课程学习] 🧪 测试视频URL可访问性: ...
[课程学习] ✅ 视频文件可访问
```
### **元数据加载:**
```
[课程学习] ✅ 视频元数据加载完成
[课程学习] 视频时长: 300 秒
[课程学习] 视频宽度: 1920
[课程学习] 视频高度: 1080
[课程学习] ✅ 视频尺寸正常,重置重试计数器
```
### **错误阶段:**
```
[课程学习] ❌❌❌ 视频播放错误 ❌❌❌
[课程学习] 错误码: -1
[课程学习] 错误信息: file not found
[课程学习] 视频URL: http://localhost:8080/profile/upload/xxx.mp4
[课程学习] 完整错误对象: {...}
```
---
## 7⃣ **总结**
### **自动处理机制:**
1.**URL测试**:提前检测可访问性
2.**黑屏修复**最多3次自动重试
3.**编码切换**自动尝试未编码URL
4.**详细日志**:便于定位问题
### **用户体验:**
- ✅ 大部分问题自动修复,无需用户干预
- ✅ 修复失败时显示详细错误信息和建议
- ✅ 不影响其他课件的学习
- ✅ 进度计算正确,不会因个别视频问题阻塞
### **不影响进度:**
- ✅ 无法播放的视频不计入完成
- ✅ 图片/PDF可正常学习并计入进度
- ✅ 用户可跳过问题视频,继续学习其他内容
---
## 🔧 **管理员排查步骤**
### **1. 检查后端日志**
```bash
# 查看课件信息
[INFO] 视频课件 893 (测试视频): 时长=300秒
[WARN] 视频课件 894 时长信息缺失或无效: null
# 查看进度计算
[INFO] 课程 123 进度计算完成: 5个已完成课件 / 8个总课件 = 62.5%
```
### **2. 检查前端日志**
```bash
# 查看URL构建
[课程学习] 🔗 URL构建信息:
- FILE_BASE_URL: http://localhost:8080
- 原始filePath: /profile/upload/2025/12/11/xxx.mp4
# 查看错误信息
[课程学习] ❌ 视频文件不存在(404)
[课程学习] 请检查数据库中的filePath是否正确
```
### **3. 验证文件**
```bash
# 检查文件是否存在
ls -lh /path/to/upload/profile/upload/2025/12/11/xxx.mp4
# 检查文件权限
chmod 644 /path/to/upload/profile/upload/2025/12/11/xxx.mp4
```
### **4. 测试URL**
```bash
# 使用curl测试
curl -I http://localhost:8080/profile/upload/2025/12/11/xxx.mp4
# 预期结果HTTP/1.1 200 OK
```
---
**最后更新:** 2025-12-11
**文档版本:** v1.0