Flutter集成Laravel登录API:如何获取并展示各类响应信息
Flutter对接Laravel登录API:精准捕获响应与错误处理
问题背景
作为Flutter新手,我正在用dio开发认证应用,Laravel登录API已通过Postman测试正常,但不知道如何对接实现以下需求:
- 捕获服务器返回的各类错误(邮箱不存在、密码错误、邮箱未验证等)并展示在客户端UI
- 获取登录成功的信息并处理
目前Auth Service已配置JSON请求头和API地址,想知道如何精准获取这些响应信息,是否需要修改现有代码。
后端Laravel登录接口代码
public function login(Request $request) { // Validate the input data $validated = $request->validate([ 'email' => 'required|string|email|max:255', 'password' => 'required|string|min:8', ]); // Find the user by email $user = User::where('email', $validated['email'])->first(); // User not found, return a 404 with specific error message if (!$user) { return response()->json([ 'message' => 'User not found.', 'type' => 'error', // Indicating it's an error ], 404); } // Check if the password is correct if (!Hash::check($validated['password'], $user->password)) { return response()->json([ 'message' => 'Please check your password.', 'type' => 'error', // Indicating it's an error ], 401); } // Check if the user is verified if (!$user->email_verified_at) { // User is not verified, resend the verification code $verificationCode = random_int(100000, 999999); $user->verification_code = $verificationCode; $user->save(); // Resend the verification email Mail::to($user->email)->send(new VerifyEmailMail($verificationCode)); // Return a 400 with informational message return response()->json([ 'message' => 'Please verify your email.', 'type' => 'info', // Informational message ], 400); } // If the user is verified, generate an API token $token = $user->createToken('auth_token')->plainTextToken; // Return 200 (OK) with success message, token, and user data return response()->json([ 'message' => 'Login successful!.', 'type' => 'success', // Success message 'token' => $token, 'user' => $user, ], 200); // OK }
现有Flutter登录请求代码
//flutter code is here Future<bool> login(String email, String password) async { try { final response = await _dio.post( loginUrl, data: json.encode({ 'email': email, 'password': password, }), ); if (response.statusCode == 200) { final token = response.data['token']; await _secureStorage.write(key: 'auth_token', value: token); return true; // Successfully logged in } else { return false; // Something went wrong with login, no errors returned } } catch (e) { if (e is DioException && e.response != null) { // Check for validation errors (422) if (e.response?.statusCode == 422) { // Returning the errors as a map throw ValidationException(e.response?.data['errors']); } } print('Login failed: $e'); return false; // Return false for other types of errors } }
修改方案与实现
现有代码仅返回bool类型,无法携带错误详情,必须修改逻辑才能精准捕获响应信息。以下是具体实现步骤:
1. 定义自定义异常类
用于区分不同类型的认证错误,方便UI层处理:
class AuthException implements Exception { final String message; final String type; AuthException(this.message, this.type); } // 保留原有的表单验证异常类 class ValidationException implements Exception { final Map<String, dynamic> errors; ValidationException(this.errors); }
2. 重构登录方法
修改返回逻辑,抛出具体异常(更符合Flutter错误处理习惯):
Future<void> login(String email, String password) async { try { // Dio可自动将Map转为JSON,无需手动json.encode final response = await _dio.post( loginUrl, data: {'email': email, 'password': password}, ); // 处理成功响应 if (response.statusCode == 200) { final token = response.data['token']; await _secureStorage.write(key: 'auth_token', value: token); return; } // 处理非200但未抛出异常的情况(极少出现) final responseData = response.data; throw AuthException( responseData['message'] ?? '登录失败', responseData['type'] ?? 'error', ); } on DioException catch (e) { if (e.response != null) { final responseData = e.response!.data; final message = responseData['message'] ?? '登录失败'; final type = responseData['type'] ?? 'error'; // 处理表单验证错误(422) if (e.response!.statusCode == 422) { throw ValidationException(responseData['errors']); } // 处理其他认证错误(404/401/400等) throw AuthException(message, type); } // 处理无响应的网络错误 throw AuthException('网络连接失败', 'error'); } catch (e) { // 处理未知错误 throw AuthException('未知错误', 'error'); } }
3. UI层调用与错误展示
在登录页面的交互逻辑中捕获异常,根据不同异常类型展示对应信息:
void _onLoginPressed() async { final email = _emailController.text.trim(); final password = _passwordController.text.trim(); try { await _authService.login(email, password); // 登录成功:展示提示并跳转首页 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('登录成功')), ); Navigator.pushReplacementNamed(context, '/home'); } on ValidationException catch (e) { // 表单验证错误:拼接错误信息展示 String errorMsg = ''; e.errors.forEach((key, value) { errorMsg += '$value\n'; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(errorMsg.trim())), ); } on AuthException catch (e) { // 认证错误:展示对应提示 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(e.message)), ); // 邮箱未验证时,可跳转验证页面 if (e.type == 'info') { Navigator.pushNamed(context, '/verify-email'); } } catch (e) { // 未知错误:通用提示 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('登录失败,请稍后重试')), ); } }
关键说明
- Dio特性:Dio默认会将非2xx状态码的响应抛出
DioException,因此大部分错误会进入catch (e)块,而非原代码的else分支。 - 响应解析:后端返回的
message和type字段可直接用于区分错误类型,无需额外判断状态码(状态码可作为辅助判断)。 - 数据传递:避免用
bool作为返回值,改用异常或包含详细信息的对象,让UI层能精准处理不同场景。
内容的提问来源于stack exchange,提问作者Cerline Jeremy
相关产品推荐
相关产品推荐

