安卓上传视频失败,绝大多数不是”Android有bug”,而是失败发生在哪一层没分清是没发出去(权限/URI)、发到一半断了(超时/后台被杀)、还是服务端根本没接收(体积限制/字段名不对),按位置分层查,通常十分钟内能定位。
先分清楚失败发生在哪一步
同样是”上传失败”,三种现象的修法完全相反,动手改代码之前,先确认自己属于哪一种。
- 点上传没反应,日志里连一个请求都没有。 问题在客户端发起前,权限、URI、文件选择器。
- 有请求,但进度条卡在某个百分比后报错。 传输层问题,超时、网络切换、进程被系统回收。
- 请求完成,但服务端返回 4xx/5xx 或”文件为空”。 服务端限制或参数格式问题。
最快的判定方式,是把同一个视频用命令行推到同一个接口,看服务端怎么回:
curl -v -F "file=@test.mp4" -F "userId=123" https://your-domain.com/api/upload
curl 成功而 App 失败,问题在客户端;curl 也失败,先把服务端调通再回来看安卓端,这一步能省掉大量无效排查。
android上传视频到服务器失败怎么办?按失败位置分层排查
还没发出去就失败:权限和 URI 这两关最容易翻车
这部分占客户端问题的比重很大,而且报错信息往往很含糊。
- 存储权限没到位。 Android 13 起读取视频要
READ_MEDIA_VIDEO,而不是老的READ_EXTERNAL_STORAGE;Android 14 又多了”仅选择部分照片视频”的授权形态READ_MEDIA_VISUAL_USER_SELECTED,只申请旧权限,在部分新机型上会直接拿不到数据。 - 把
content://当成文件路径用。 相册选出来的 URI 是内容 URI,new File(uri.getPath())必然抛FileNotFoundException,正确做法是用ContentResolver.openInputStream(uri)读取,或先复制到应用缓存目录再上传。 - 没走 FileProvider。 自己拼
file://路径在 Android 7.0 以上会触发FileUriExposedException,通过 Intent 分享视频给其他应用时尤其明显。 - 用了分区存储之外的绝对路径。 直接把
/storage/emulated/0/DCIM/xxx.mp4写死在代码里,换了机型就失效。
排查动作很直接:在发起上传前打一行日志,输出 URI 的 scheme、文件大小、MIME 类型。size 为 0 或 scheme 不是 content/file,基本可以当场定位。
发出去了但中途断:安卓上传视频到服务器超时是什么原因
这是提问量最多的场景,原因通常落在下面几处:
- 超时时间设置不合理。 OkHttp 默认的读写超时是 10 秒级别,几十兆的视频在弱网下根本传不完,会抛
SocketTimeoutException,上传场景需要单独调大writeTimeout、readTimeout,或者干脆对上传请求设为 0 表示不限制。 - 切后台被系统冻结。 Android 8.0 之后后台服务受限,用户点完上传切去刷微信,进程进入后台就可能被挂起甚至杀掉,大文件上传应当放进前台服务,并在 Android 14 及以上正确声明
foregroundServiceType(如dataSync),否则会抛MissingForegroundServiceTypeException。 - 厂商省电策略介入。 部分国产 ROM 对后台网络有额外限制,息屏后直接断网,测试时把屏幕常亮和息屏两种状态都跑一遍,能快速区分。
- 网络在 Wi-Fi 和蜂窝之间切换。 连接复用被打断,表现为传到一半突然失败。
服务端返回 4xx/5xx:先分清真失败还是假失败
客户端看到 500 就以为服务端崩了,其实很多是体积限制和参数问题。
| 现象 | 常见原因 | 优先检查点 |
|---|---|---|
| 413 Payload Too Large | 反向代理或框架限制请求体 | Nginx client_max_body_size(默认较小)、Spring Boot max-file-size、PHP upload_max_filesize |
| 500 且服务端日志有 MaxUploadSizeExceeded | 框架层拦截 | 上传大小配置与异常处理器 |
| 400 缺少文件 | 表单字段名不一致 | 客户端 file 与服务端接收字段是否同名 |
| 401/403 | 签名、Token 过期 | 上传耗时长,Token 中途过期 |
| 200 但文件损坏 | 分片顺序或编码问题 | 服务端合并逻辑、Content-Type |
假失败也要留意:服务端其实已经存好了文件,但响应超时,客户端重试导致重复上传,服务端做一次基于文件哈希的幂等判断,能省掉很多麻烦。
大文件必看:安卓手机上传大视频文件失败解决方法
别把视频整个读进内存
用 readBytes() 或 ByteArrayOutputStream 把几百兆视频一次性读进内存,低端机上大概率 OutOfMemoryError,日志里表现为上传前就崩,正确姿势是流式上传,OkHttp 的 RequestBody 从 InputStream 边读边写:
val body = object : RequestBody() {
override fun contentType() = "video/mp4".toMediaType()
override fun writeTo(sink: BufferedSink) {
contentResolver.openInputStream(uri)?.use { input ->
sink.writeAll(input.source())
}
}
}
分片上传和断点续传怎么落地
单次上传和分片上传的取舍,取决于视频体积和网络质量。
| 方案 | 适用场景 | 代价 |
|---|---|---|
| 单次直传 | 几十兆以内、Wi-Fi 环境 | 失败即从头再来 |
| 分片上传 | 百兆以上、移动网络 | 需要服务端支持合并与校验 |
| 断点续传 | 用户可能中断重试 | 需要记录分片状态 |
实践中比较稳的做法是:按固定大小切片(例如数兆一片),每片带序号和总片数,全部成功后调用合并接口,客户端把已上传的分片索引存到本地,重试时跳过,这样即使中途失败,用户也不用从零开始。
Android WebView上传视频失败怎么解决
H5 页面里点”选择视频”没反应,多半是原生侧没接管文件选择。
- 没有实现
onShowFileChooser。 WebChromeClient 里必须重写该方法,拉起系统选择器并把结果回传给FileChooserParams,否则点击毫无反应。 - 回传的 URI 权限没放开。 拿到
content://后要授予临时读权限,否则网页侧读不到文件。 - 明文 HTTP 被拦。 Android 9 起默认禁止明文流量,接口还是
http://时会直接失败,要么升级 HTTPS,要么配置network_security_config精确放行域名不建议全局开启usesCleartextTraffic。 - 自签名证书导致握手失败。 测试环境常见
SSLHandshakeException,用正式证书或把测试证书装进信任链,不要在生产包里写”信任所有证书”的代码。
安卓和iOS上传视频失败的区别:别照抄iOS的结论
同一套接口,iOS 能传、安卓不行,是很常见的反馈,差异主要在:
- URI 模型不同。 iOS 给的是沙盒文件路径,安卓给的是内容 URI,直接套用 iOS 的”读文件路径”逻辑必挂。
- 后台策略不同。 iOS 有较明确的后台上传时间窗口,安卓厂商定制更深,息屏断网更普遍。
- 权限粒度不同。 安卓 13/14 的媒体权限分层更细,需要按版本分支申请。
- 体积限制暴露点不同。 安卓端更容易在内存和超时上先出问题,iOS 则更常见于服务端限制。
所以看到”iOS 没问题”,不要反推安卓代码有 bug,先按上一节的分层法确认失败位置。
服务器部署地域与链路:容易被忽略的隐性坑
服务部署在华南机房、用户集中在华北,跨运营商链路抖动时,长连接更容易在中途被掐断,表现就是”特定地区用户上传失败率高”,这类问题在客户端日志里几乎看不出来,需要服务端按地域统计成功率,同一运营商、同一地域内部正常,跨地域失败,基本可以锁定链路而非代码。
免费的排查手段和付费上传SDK,什么时候该花钱
先用免费手段把问题收敛:adb logcat 过滤自己应用的包名看异常栈,用 curl 复现服务端行为,用抓包工具确认请求是否真的发出、响应码是什么,这三步能覆盖大部分场景。
如果业务对断点续传、秒传、多端一致性有硬要求,自研成本会明显上升。行业共识认为,视频类应用在中后期引入成熟的上传 SDK 往往比自研更划算,但前提是基础链路已经跑通SDK 解决不了配置错误和权限问题。
最后收束
安卓上传视频失败从来不是单一原因,把”没发出、传一半、服务端拒收”三段切开,逐段用日志和 curl 验证,绝大多数问题都能在半小时内锁定,真正拖时间的往往不是技术难度,而是在错误的层级上反复改代码。
Q&A:android上传视频到服务器失败怎么办
日志里完全看不到网络请求,该从哪里查起?
先确认权限是否按系统版本正确申请,再打印选中文件的 URI scheme 和大小,scheme 为 content 却按文件路径处理,或 size 为 0,是最常见的两类原因,若点击后连选择器都没弹出,检查是否遗漏了 onShowFileChooser 或权限回调被中断。
小视频能传,超过一定体积就失败,通常是哪里的问题?
优先查三处:反向代理的请求体上限、应用框架的上传大小配置、客户端超时设置,据公开的框架默认配置,Nginx 与部分 Web 框架的默认上传上限都偏小,几十兆的视频很容易触发 413 或框架层的体积异常,把限制调大后仍失败,再考虑改成分片上传。
上传到一半切到后台就断了,有没有不改服务端的办法?
有,把上传放进前台服务并显示通知,避免进程被系统回收;同时在客户端记录已完成的分片或字节偏移,重新回到前台后从断点继续,业内专家指出,移动端长耗时网络任务的核心矛盾在于进程存活,而不是带宽本身,先解决存活问题,成功率会明显改善。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/783638.html


