Flutter对接PHP API登录时获取用户数据触发Socket异常排查
问题:Flutter对接PHP API登录出现Socket异常
原本Flutter应用对接PHP API的登录功能运行正常,添加获取客户端ID和姓名并用于页面间传递的逻辑后出现Socket异常,且该异常在添加PHP中的userID返回逻辑前就已出现,添加后问题仍存在。
相关代码
PHP代码
include_once "database.php"; include_once "cores.php"; $phone = $_POST['phone']; $select = "SELECT * FROM `client` WHERE `phone`='$phone' AND `status`='Active' "; $run = mysqli_query($connect, $select); if (mysqli_num_rows($run) > 0) { $userData = array(); while ($row = mysqli_fetch_assoc($run)) { $userData = $row; } echo json_encode( array( "check" => true, "userID" => $userData[0] ) ); } else { echo json_encode(array("check" => false)); }
Flutter代码
Future<void> LoginClient() async { if (phone.text.isNotEmpty) { try { var validate = await http.post( Uri.parse(ApisConnect.checkPhoneNumberApi), body: { "phone" : phone.text } ); var response1 = jsonDecode(validate.body); if (response1["exists"] == true) { var login = await http.post( Uri.parse(ApisConnect.loginApi), body: { "phone": phone.text, }, ); var response2 = jsonDecode(login.body); if (response2["check"] == true) { Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => DashboardScreen())); User userInfo = User.fromJson(response2["userID"]); Fluttertoast.showToast(msg: 'Logined Successfully,'); } else if(response2['check'] == false) { Fluttertoast.showToast(msg: 'You Are blocked, If you have any error call Techneical Support'); } } else { Fluttertoast.showToast(msg: 'This Number not signed, sign up first.'); } } catch (e) { Fluttertoast.showToast(msg: 'Error: $e'); } } else { Fluttertoast.showToast(msg: 'Fill The field first'); } }
排查与修复建议
1. 修正PHP代码错误
- 关联数组索引错误:
mysqli_fetch_assoc返回的是关联数组,$userData[0]不存在,需替换为数据库实际的用户ID字段名(如$userData['id']或$userData['client_id']),否则会触发PHP警告,导致返回内容混入错误信息,破坏JSON格式。 - 清除输出缓冲区:在
echo json_encode前添加ob_clean();,确保响应仅返回纯JSON数据,避免额外输出(如空格、警告)干扰Flutter解析。 - 防范SQL注入:改用预处理语句,避免直接拼接SQL参数,提升安全性同时避免潜在语法错误。
修正后的PHP代码示例:
include_once "database.php"; include_once "cores.php"; $phone = isset($_POST['phone']) ? $_POST['phone'] : ''; // 预处理语句防SQL注入 $select = "SELECT * FROM `client` WHERE `phone`=? AND `status`='Active' "; $stmt = mysqli_prepare($connect, $select); mysqli_stmt_bind_param($stmt, "s", $phone); mysqli_stmt_execute($stmt); $run = mysqli_stmt_get_result($stmt); if (mysqli_num_rows($run) > 0) { $userData = mysqli_fetch_assoc($run); ob_clean(); echo json_encode( array( "check" => true, "userID" => $userData['id'], // 替换为实际字段名 "name" => $userData['name'] // 如需返回姓名,添加对应字段 ) ); } else { ob_clean(); echo json_encode(array("check" => false)); }
2. 调整Flutter代码逻辑
- 页面跳转时机:先获取用户信息再执行页面跳转,避免
Navigator.pushReplacement后上下文失效导致的异常。 - 异常详情排查:在catch块中打印完整错误信息到控制台,区分是Socket连接异常还是JSON解析异常。
- 用户信息传递:跳转时直接将用户信息传入目标页面,确保数据传递有效。
修正后的Flutter代码示例:
Future<void> LoginClient() async { if (phone.text.isNotEmpty) { try { var validate = await http.post( Uri.parse(ApisConnect.checkPhoneNumberApi), body: {"phone": phone.text} ); var response1 = jsonDecode(validate.body); if (response1["exists"] == true) { var login = await http.post( Uri.parse(ApisConnect.loginApi), body: {"phone": phone.text}, ); var response2 = jsonDecode(login.body); if (response2["check"] == true) { // 先解析用户信息 User userInfo = User.fromJson({ "id": response2["userID"], "name": response2["name"] }); // 跳转并传递用户信息 Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => DashboardScreen(userInfo: userInfo) ) ); Fluttertoast.showToast(msg: '登录成功'); } else if(response2['check'] == false) { Fluttertoast.showToast(msg: '您已被封禁,如有问题请联系技术支持'); } } else { Fluttertoast.showToast(msg: '该号码未注册,请先注册'); } } catch (e) { print('错误详情:$e'); // 控制台打印完整错误 Fluttertoast.showToast(msg: '错误:${e.toString()}'); } } else { Fluttertoast.showToast(msg: '请先填写手机号'); } }
3. 额外排查步骤
- 用Postman或curl测试API接口,确认返回的JSON格式是否正确,无额外错误输出。
- 检查Flutter控制台的异常详情,明确是网络连接问题还是数据解析问题。
- 确认服务器防火墙、请求频率限制未阻止Flutter应用的请求。
- 检查AndroidManifest.xml(Android)或Info.plist(iOS)的网络权限配置是否完整。
内容的提问来源于stack exchange,提问作者King Yossef Reda
相关产品推荐
相关产品推荐

