fix: 登录失败自动自检三个服务端口并展示 SDK 原始错误(B-58)
- IMService 记录 onConnectFailed 的 code/error(lastConnectError) - SDK 未初始化成功时 login 直接抛错,不再无限等待 - 登录页失败提示下附自检结果:账号服务/消息接口/消息长连接 通不通 - 版本号 1.0.2+3
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../config.dart';
|
||||
import '../services/auth_api.dart';
|
||||
import '../services/call_service.dart';
|
||||
import '../services/im_service.dart';
|
||||
@@ -92,14 +94,52 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
MaterialPageRoute(builder: (_) => const HomeScreen()),
|
||||
);
|
||||
} on AuthException catch (e) {
|
||||
setState(() => _error = e.message);
|
||||
await _fail(e.message);
|
||||
} catch (_) {
|
||||
setState(() => _error = '登录出错了,请稍后再试');
|
||||
await _fail('登录出错了,请稍后再试');
|
||||
} finally {
|
||||
if (mounted) setState(() => _logging = false);
|
||||
}
|
||||
}
|
||||
|
||||
/// 登录失败:在提示下方附上服务器自检结果,方便远程定位是哪一段不通
|
||||
Future<void> _fail(String msg) async {
|
||||
final parts = [msg];
|
||||
try {
|
||||
parts.add(await _diagnoseServer());
|
||||
} catch (_) {
|
||||
// 自检本身失败不影响原提示
|
||||
}
|
||||
final sdkErr = IMService.instance.lastConnectError;
|
||||
if (sdkErr != null && sdkErr.isNotEmpty) parts.add('消息组件报告:$sdkErr');
|
||||
if (mounted) setState(() => _error = parts.join('\n'));
|
||||
}
|
||||
|
||||
/// 逐个探测三个服务端口:能拿到任何 HTTP 响应就算通
|
||||
Future<String> _diagnoseServer() async {
|
||||
final dio = Dio(BaseOptions(
|
||||
connectTimeout: const Duration(seconds: 5),
|
||||
receiveTimeout: const Duration(seconds: 5),
|
||||
));
|
||||
Future<String> probe(String label, String url) async {
|
||||
try {
|
||||
await dio.get(url);
|
||||
return '$label通';
|
||||
} on DioException catch (e) {
|
||||
return e.response != null ? '$label通' : '$label不通';
|
||||
} catch (_) {
|
||||
return '$label不通';
|
||||
}
|
||||
}
|
||||
|
||||
final results = await Future.wait([
|
||||
probe('账号服务', '$authApiBase/api/health'),
|
||||
probe('消息接口', '$apiAddr/'),
|
||||
probe('消息长连接', 'http://$serverHost:$wsPort/'),
|
||||
]);
|
||||
return '自检:${results.join(',')}';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
||||
@@ -36,6 +36,9 @@ class IMService extends ChangeNotifier {
|
||||
/// 与服务器的连接状态(断网横幅用)
|
||||
ConnectStatus connectStatus = ConnectStatus.idle;
|
||||
|
||||
/// 最近一次连接失败的原始错误(诊断展示用)
|
||||
String? lastConnectError;
|
||||
|
||||
/// 是否已登录
|
||||
bool loggedIn = false;
|
||||
|
||||
@@ -108,12 +111,14 @@ class IMService extends ChangeNotifier {
|
||||
connectStatus = ConnectStatus.connecting;
|
||||
notifyListeners();
|
||||
},
|
||||
onConnectSuccess: () {
|
||||
connectStatus = ConnectStatus.success;
|
||||
notifyListeners();
|
||||
},
|
||||
onConnectFailed: (code, error) {
|
||||
connectStatus = ConnectStatus.failed;
|
||||
lastConnectError = '$code $error';
|
||||
notifyListeners();
|
||||
},
|
||||
onConnectSuccess: () {
|
||||
connectStatus = ConnectStatus.success;
|
||||
lastConnectError = null;
|
||||
notifyListeners();
|
||||
},
|
||||
onKickedOffline: _forceLogout,
|
||||
@@ -191,6 +196,10 @@ class IMService extends ChangeNotifier {
|
||||
/// 登录(init 之后调用)。userID/token 来自公司账号登录接口。
|
||||
Future<void> login({required String userID, required String token}) async {
|
||||
await init();
|
||||
if (!sdkReady) {
|
||||
// initSDK 返回 false:SDK 没初始化成功,直接登录会无限等待
|
||||
throw StateError('消息组件初始化失败');
|
||||
}
|
||||
final user = await OpenIM.iMManager.login(
|
||||
userID: userID,
|
||||
token: token,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
name: changlian
|
||||
description: 畅联 —— 公司内部通讯 App(手机端)
|
||||
publish_to: "none"
|
||||
version: 1.0.1+2
|
||||
version: 1.0.2+3
|
||||
|
||||
environment:
|
||||
sdk: ">=3.6.0 <4.0.0"
|
||||
|
||||
Reference in New Issue
Block a user