guoyu/视频异常处理逻辑.md
2025-12-11 23:28:07 +08:00

9.4 KiB
Raw Blame History

视频异常处理逻辑总结

📊 整体流程

视频加载 → URL测试 → 元数据加载 → 黑屏检测 → 播放 → 错误处理

1 视频URL测试testVideoUrl

触发时机:

  • 加载视频课件时(loadCourseware

处理逻辑:

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

触发时机:

  • 视频元数据加载完成时

检测逻辑:

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. 根据错误码判断

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编码切换

// 构建原始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. 显示详细错误信息

uni.showModal({
    title: '视频播放失败',
    content: `
        ${errorMsg}
        
        请检查:
        1. 服务器是否运行
        2. 视频文件是否存在
        3. 网络连接是否正常
        
        服务器: ${config.FILE_BASE_URL}
        路径: ${courseware.filePath}
    `,
    showCancel: false,
    confirmText: '知道了'
})

4 视频加载失败的完整处理流程

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. 不影响学习进度

关键逻辑:

// 即使视频无法播放,图片/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. 检查后端日志

# 查看课件信息
[INFO] 视频课件 893 (测试视频): 时长=300秒
[WARN] 视频课件 894 时长信息缺失或无效: null

# 查看进度计算
[INFO] 课程 123 进度计算完成: 5个已完成课件 / 8个总课件 = 62.5%

2. 检查前端日志

# 查看URL构建
[课程学习] 🔗 URL构建信息:
  - FILE_BASE_URL: http://localhost:8080
  - 原始filePath: /profile/upload/2025/12/11/xxx.mp4

# 查看错误信息
[课程学习] ❌ 视频文件不存在(404)
[课程学习] 请检查数据库中的filePath是否正确

3. 验证文件

# 检查文件是否存在
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

# 使用curl测试
curl -I http://localhost:8080/profile/upload/2025/12/11/xxx.mp4

# 预期结果HTTP/1.1 200 OK

最后更新: 2025-12-11 文档版本: v1.0