Flutter使用Firestore闲置15-20分钟首次请求报UNAVAILABLE错误如何解决
- 该问题是Firebase SDK维持的长连接在设备闲置阶段被中断导致的:Firestore默认会与后端维持长连接来提升请求效率,当设备长时间处于闲置状态时,要么是系统的省电策略主动切断了后台闲置的网络连接,要么是运营商的NAT网关超时回收了长时间无数据传输的TCP连接,此时SDK未及时感知到连接已失效。
- 首次发起请求时使用已经失效的连接触发
UNAVAILABLE错误,SDK在报错后会自动重建新连接,因此第二次请求就能正常发送。
相关错误日志:
V/NativeCrypto( 4054): Read error: ssl=0xbe39a7c8: I/O error during system call, Connection reset by peer
V/NativeCrypto( 4054): Write error: ssl=0xbe39a7c8: I/O error during system call, Broken pipe
V/NativeCrypto( 4054): SSL shutdown failed: ssl=0xbe39a7c8: I/O error during system call, Success
W/Firestore( 4054): (23.0.3) [WatchStream]: (a4f0ee) Stream closed with status: Status{code=UNAVAILABLE, description=End of stream or IOException, cause=null}.
[cloud_firestore/unavailable] The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff.

可根据业务场景选择以下任意一种或组合使用:
- 封装通用的Firestore请求重试逻辑
捕获cloud_firestore/unavailable类型的异常,采用指数退避策略自动重试,无需用户手动点击两次。示例代码如下:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:retry/retry.dart'; // 通用请求封装 Future<T> executeFirestoreOperation<T>(Future<T> Function() operation) async { const retryConfig = RetryOptions( maxAttempts: 3, delayFactor: Duration(milliseconds: 100), retryIf: (error) => error is FirebaseException && error.code == 'unavailable', ); return retryConfig.retry(operation); } // 业务侧使用示例 Future<void> loadUserData(String uid) async { final userDoc = await executeFirestoreOperation( () => FirebaseFirestore.instance.collection('users').doc(uid).get(), ); // 后续业务逻辑 }
如果不想引入第三方retry包,也可以手动实现简单的重试逻辑。
- 应用回到前台时主动重置连接
监听应用生命周期,当应用从后台切回前台时,主动重置Firestore的网络连接,提前重建有效连接避免用户首次操作失败。示例代码如下:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class MainPageState extends State<MainPage> with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // 应用从后台恢复到前台时重置连接 if (state == AppLifecycleState.resumed) { unawaited(FirebaseFirestore.instance.disableNetwork()); unawaited(FirebaseFirestore.instance.enableNetwork()); } } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } }
- 辅助优化(可选)
针对Android平台可以引导用户开启应用的电池优化豁免权限,减少系统对闲置网络连接的主动切断,该方案需要用户授权,仅作为补充优化手段。
内容的提问来源于stack exchange,提问作者Hammad Parveez

