← 返回文章列表
李奕锦的个人网站所属专题:侦探式排查实录

技术排查:移动端 H5 拍照上传失败原因分析——WebView 生命周期与 SSE 长连接冲突深度解密

更新于 2025-11-02年份:2025字数:1,850阅读时长:6 分钟

针对移动端 H5 拍照上传时随机出现的失败现象进行排查。最终定位为 WebView 进程切换导致 SSE (Server-Sent Events) 断连,以及 File 对象在组件封装过程中的非标准化处理。本文提供高性能 Hybrid 应用的保活与文件处理方案。

做移动端 AI 图片识别时踩了个坑:从相册选图上传一切正常,换成直接拍照就必现失败,接口报 Network Error 或 Abort。

折腾了好一阵才把根因理清。把排查过程整理下来,顺便聊聊 WebView、SSE、File API 在 Hybrid 里的保活和文件处理。

一、现象

相册选图正常,相机拍摄后页面闪退或请求中断。

从相册选图时,用户 stays 在当前 H5 页,只是短暂切出去选图再回来,连接一直在线。直接拍照不同——会跳转到系统相机 App,当前页相当于进入后台,document.hidden 变为 true。

二、根因定位

连接层:后台 SSE 长连接因 WebView 内存回收机制被动切断

H5 页面与服务器通过 Server-Sent Events (SSE) 维持长连接。当用户调起相机时,WebView 进程可能被系统回收或置于低优先级,不少 SSE 库的默认策略是:页面不可见(document.hidden === true)时关闭连接以节省资源。

于是等你拍完照回到 H5,连接早已被关掉,依赖该连接的上传请求自然失败。

解决方案:明确告诉 SSE 库,页面暂时不可见时不要关闭连接。例如配置 openWhenHidden: true。同时实现 SSE 断线重连与状态保活机制,确保从相机返回后连接仍有效。

数据层:自定义组件库对 File 对象的封装未兼容 file.raw 原始流,导致序列化丢失

另一头的问题是:我们想上传的是真实的文件流(Blob),但像 Element Plus Upload 这类组件会对文件做一层封装(Proxy 或包装对象)。如果直接把组件给的那个对象塞进 FormData,服务端收到的可能变成 [object Object] 之类的字符串,而不是真正的二进制数据。

所以上传前要"解包":不管是组件直接给的 file 还是包装过的,都统一取真正的文件实例再放进 FormData,例如使用 file.raw(视具体组件 API 而定),保证寄出去的是文件本身,确保二进制流在上传链路中的完整性。

三、解决方案

一是做 SSE 断线重连和状态保活;二是重构文件处理逻辑,上传前对 file 做 raw 解包,确保 Blob 完整。

修完之后,iOS 和 Android 上拍照再上传都稳了。问题本身不复杂,主要是被"相册正常、拍照必挂"的现象带偏,一度以为是相机或机型兼容,其实还是页面生命周期和数据结构这两块。

阅读时长:6 分钟


文档信息

版权声明:自由转载-非商用-非衍生-保持署名(CC BY-NC-ND 3.0)

原文链接:https://yijinlee.com/share-future/article-2

作者:李奕锦

商业用途或修改衍生请联系授权。


TL;DR

  • 连接层:WebView 进后台导致 SSE 长连接被动切断,配置 openWhenHidden 保活并实现断线重连。
  • 数据层:组件库对 File 的封装未兼容 file.raw 原始流,上传前解包确保 Blob 完整性。
  • 排查路径:相册正常、拍照必挂 → Page Visibility → SSE 库策略 → 请求参数序列化。
Tags:WebViewSSE (Server-Sent Events)File APIJavaScriptiOS/Android Hybrid

该专题下的阅读路径

现象分析 → 根因定位 → 解决方案复盘