You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ExoPlayer DownloadService下载HLS视频时401崩溃问题排查

ExoPlayer下载HLS时偶尔因401崩溃的排查与解决

可能的原因

  • 令牌时效性与请求时序差异:预授权令牌在下载过程中过期(如下载大文件时,分片请求晚于m3u8请求,令牌刚好在分片请求时失效)。你用过期链接测试时是初始请求就触发401,ExoPlayer下载管理器能正常标记失败;但下载过程中令牌过期导致的401,因未被正确捕获而触发崩溃。
  • HttpDataSource错误处理配置缺失:默认的DefaultHttpDataSource会对非200-299的响应码抛出InvalidResponseCodeException,如果这个异常未被ExoPlayer下载逻辑捕获(比如并发线程池未处理),就会导致应用崩溃。
  • 并发请求的令牌冲突:使用固定线程池并发下载时,多个分片请求同时使用同一令牌,可能触发服务器的令牌校验限制(如同一令牌并发请求次数上限),导致部分请求返回401。
  • 缓存与令牌不匹配:自定义的OPDownloadCacheKeyFactory若未将令牌纳入缓存key生成逻辑,可能缓存了带旧令牌的m3u8文件,后续分片请求使用过期令牌。

解决与排查步骤

1. 先解决崩溃问题:配置HttpDataSource捕获401异常

修改你的getHttpDataSourceFactory方法,允许无效响应码或自定义异常处理,避免未捕获的异常导致崩溃:

private fun getHttpDataSourceFactory(context: Context): HttpDataSource.Factory {
    return DefaultHttpDataSource.Factory()
        .setUserAgent("Your-App-User-Agent")
        // 允许非200响应码,避免抛出异常导致崩溃,ExoPlayer会自动标记下载失败
        .setAllowInvalidResponseCodes(true)
        // 若需要动态更新令牌,可添加请求头拦截逻辑
        .setDefaultRequestProperties(
            mapOf("Authorization" to "Bearer ${yourTokenProvider.getValidToken()}")
        )
}

或者自定义HttpDataSource,在请求前刷新令牌,确保每次请求用最新令牌:

class TokenRefreshingHttpDataSourceFactory(
    private val tokenProvider: () -> String
) : HttpDataSource.Factory {
    override fun createDataSource(): HttpDataSource {
        return object : DefaultHttpDataSource("Your-App-User-Agent") {
            override fun open(dataSpec: DataSpec): Long {
                // 每次请求前更新授权头,确保令牌有效
                val updatedDataSpec = dataSpec.buildUpon()
                    .setRequestProperty("Authorization", "Bearer ${tokenProvider.invoke()}")
                    .build()
                return try {
                    super.open(updatedDataSpec)
                } catch (e: HttpDataSource.InvalidResponseCodeException) {
                    if (e.responseCode == 401) {
                        // 可选:在这里触发令牌刷新,重试请求
                        // val newToken = refreshToken()
                        // val retrySpec = updatedDataSpec.buildUpon()
                        //     .setRequestProperty("Authorization", "Bearer $newToken")
                        //     .build()
                        // super.open(retrySpec)
                        throw e // 抛出异常让ExoPlayer标记下载失败,而非崩溃
                    } else {
                        throw e
                    }
                }
            }
        }
    }
}

2. 排查401的根源

  • 开启ExoPlayer日志:添加日志配置,查看崩溃时的请求URL、响应头和令牌信息,确认是m3u8请求还是分片请求触发401。
  • 模拟令牌过期场景:启动下载后,手动让令牌失效(如调用后端接口吊销令牌),观察是否能复现崩溃。
  • 检查服务器日志:查看返回401的请求详情,确认是令牌过期、无效还是并发限制导致。
  • 校验缓存key逻辑:确保OPDownloadCacheKeyFactory生成的缓存key包含令牌的唯一标识,避免缓存旧的授权内容。

3. 优化下载逻辑

  • 限制并发下载数:若服务器对同一令牌的并发请求有限制,可降低MAX_PARALLEL_DOWNLOADS的值。
  • 添加下载监听的错误处理:在OPDownloadListener中监听onDownloadFailed事件,针对401错误做重试或用户提示。

内容的提问来源于stack exchange,提问作者Akshansh Choudhary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 18:42:47