# 异常处理使用指南 ## 概述 本项目采用统一的异常处理机制,所有API接口的错误都将返回统一的JSON格式。开发者只需要使用简单的方法就能抛出业务异常。 ## 快速使用 ### 1. 引入异常处理器 ```php use App\Exceptions\Handler; ``` ### 2. 基本用法 ```php // 最基本的用法 - 抛出默认错误 Handler::throw('用户不存在'); // 指定错误码 Handler::throw('用户不存在', 404); // 使用别名方法 Handler::error('参数错误', 400); // 操作失败 Handler::fail('删除失败'); ``` ## 可用方法 ### Handler::throw($message, $code = 400) **功能**: 抛出业务异常(主要方法) ```php Handler::throw('数据不存在', 404); Handler::throw('权限不足', 403); Handler::throw('操作失败'); // 默认错误码400 ``` ### Handler::error($message, $code = 400) **功能**: throw方法的别名,使用习惯更友好 ```php Handler::error('用户名已存在', 409); Handler::error('参数错误'); ``` ### Handler::fail($message = '操作失败') **功能**: 快速抛出操作失败异常 ```php Handler::fail(); // 默认消息:操作失败 Handler::fail('用户创建失败'); Handler::fail('文件上传失败'); ``` ## 使用场景 ### 1. 控制器中使用 ```php status === 0) { Handler::throw('用户已被禁用', 403); } return $this->SuccessObject($user); } public function store(Request $request) { $username = $request->input('username'); // 检查用户名是否存在 if (User::where('username', $username)->exists()) { Handler::error('用户名已存在', 409); } try { $user = User::create($request->all()); return $this->SuccessObject($user); } catch (\Exception $e) { Handler::fail('用户创建失败'); } } public function destroy($id) { $user = User::find($id); if (!$user) { Handler::throw('用户不存在', 404); } // 不能删除管理员 if ($user->is_admin) { Handler::error('不能删除管理员账户', 403); } if (!$user->delete()) { Handler::fail('用户删除失败'); } return $this->Success(['message' => '删除成功']); } } ``` ### 2. 服务类中使用 ```php usernameExists($data['username'])) { Handler::error('用户名已存在', 409); } // 创建用户 try { return User::create($data); } catch (\Exception $e) { Handler::fail('用户创建失败'); } } public function updateUserStatus($userId, $status) { $user = User::find($userId); if (!$user) { Handler::throw('用户不存在', 404); } if ($user->is_admin && $status === 0) { Handler::error('不能禁用管理员账户', 403); } $user->status = $status; if (!$user->save()) { Handler::fail('状态更新失败'); } return $user; } private function usernameExists($username) { return User::where('username', $username)->exists(); } } ``` ### 3. 中间件中使用 ```php user(); if (!$user) { Handler::error('用户未登录', 401); } if ($user->status === 0) { Handler::throw('账户已被禁用', 403); } if ($user->deleted) { Handler::throw('账户不存在', 404); } return $next($request); } } ``` ### 4. 模型中使用 ```php password = bcrypt($newPassword); if (!$this->save()) { Handler::fail('密码修改失败'); } } public function assignRole($roleId) { if ($this->is_admin) { Handler::error('管理员不能修改角色', 403); } $role = Role::find($roleId); if (!$role) { Handler::throw('角色不存在', 404); } $this->role_id = $roleId; if (!$this->save()) { Handler::fail('角色分配失败'); } } } ``` ## 响应格式 所有异常都会返回统一的JSON格式: ### 成功响应 ```json { "success": true, "message": "success", "code": 200, "data": { // 具体数据 } } ``` ### 异常响应 ```json { "success": false, "message": "具体错误信息", "code": 400, "data": null } ``` ### 参数验证错误 ```json { "success": false, "message": "参数错误", "code": 422, "data": null, "errors": { "username": ["用户名不能为空"], "email": ["邮箱格式不正确"] } } ``` ## 常用错误码 | 错误码 | 说明 | 使用场景 | |--------|------|----------| | 400 | 通用错误 | 默认业务错误 | | 401 | 未授权 | 用户未登录 | | 403 | 权限不足 | 没有操作权限 | | 404 | 资源不存在 | 数据不存在 | | 409 | 冲突 | 数据已存在 | | 422 | 参数错误 | 验证失败 | | 500 | 服务器错误 | 系统异常 | ## 测试异常处理 项目提供了测试接口来验证异常处理(仅开发环境可用): ```bash # 测试参数验证异常 curl -X POST http://localhost:8000/admin/test/validation \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' # 测试业务异常 curl -X GET http://localhost:8000/admin/test/business-exception \ -H "Authorization: Bearer YOUR_TOKEN" # 测试参数错误 curl -X GET http://localhost:8000/admin/test/param-error \ -H "Authorization: Bearer YOUR_TOKEN" # 测试操作失败 curl -X GET http://localhost:8000/admin/test/fail \ -H "Authorization: Bearer YOUR_TOKEN" # 测试系统异常 curl -X GET http://localhost:8000/admin/test/system-exception \ -H "Authorization: Bearer YOUR_TOKEN" ``` ## 最佳实践 ### 1. 异常使用原则 - **业务逻辑错误**: 使用 `Handler::throw()` 或 `Handler::error()` - **操作失败**: 使用 `Handler::fail()` - **参数验证**: 使用Laravel的Validation,会自动处理 - **系统错误**: 直接throw Exception,会自动处理 ### 2. 错误信息编写 - 错误信息要简洁明确 - 面向用户,避免技术术语 - 提供解决建议(如果可能) ```php // ✅ 好的错误信息 Handler::error('用户名已存在,请尝试其他用户名'); Handler::throw('文件大小不能超过2MB', 413); // ❌ 不好的错误信息 Handler::error('数据库约束冲突'); Handler::throw('系统错误'); ``` ### 3. 错误码规范 ```php // 常用错误码 Handler::throw('数据不存在', 404); Handler::throw('权限不足', 403); Handler::throw('数据已存在', 409); Handler::error('参数错误', 400); ``` ### 4. 性能考虑 - 不要在循环中频繁抛出异常 - 异常只用于错误处理,不要用于控制程序流程 - 在抛出异常前先做基本检查 ```php // ✅ 好的做法 if (empty($users)) { return $this->Success([]); // 返回空数据 } foreach ($users as $user) { // 正常处理 } // ❌ 不好的做法 foreach ($users as $user) { if ($user->invalid) { Handler::error('用户无效'); // 在循环中抛异常 } } ``` ## 注意事项 1. **生产环境**: 系统异常会隐藏详细信息,只返回"服务器错误" 2. **开发环境**: 系统异常会显示详细的调试信息 3. **日志记录**: 所有异常都会自动记录到日志文件 4. **测试路由**: 仅在开发环境可用,生产环境会自动禁用 ## 迁移指南 如果您之前使用的是复杂的异常处理方式,可以按以下方式迁移: ```php // 之前的方式 throw new BusinessException(ResponseEnum::DATA_NOT_FOUND_ERROR, '用户不存在'); // 现在的方式 Handler::throw('用户不存在', 404); // 之前的方式 $this->throwBusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR, '参数错误'); // 现在的方式 Handler::error('参数错误'); ``` 这样大大简化了异常处理的使用,让开发更加便捷! ## API认证中间件 为了解决API项目中认证失败时返回重定向错误的问题,我们创建了专用的API认证中间件: ### 中间件文件 - `app/Http/Middleware/AdminApiAuthenticate.php` - 专用API认证中间件 ### 功能特点 1. **统一的401错误响应**:认证失败时返回JSON格式的401错误,而不是重定向 2. **支持Sanctum认证**:默认使用`sanctum`守护器进行认证 3. **扩展性强**:可轻松扩展支持其他认证方式 ### 响应格式 ```json { "success": false, "message": "未授权访问,请先登录", "code": 401, "data": null } ``` ### 使用方式 在路由中使用`admin.auth`中间件: ```php Route::middleware('admin.auth')->group(function () { // 需要认证的路由 }); ``` ### 扩展示例 如果需要支持更多认证方式,可以修改中间件: ```php public function handle(Request $request, Closure $next, ...$guards) { $guards = empty($guards) ? ['sanctum'] : $guards; // 可以在这里添加其他认证逻辑 // 例如:JWT、API Key等 foreach ($guards as $guard) { if (auth()->guard($guard)->check()) { auth()->shouldUse($guard); return $next($request); } } // 自定义认证失败响应 return response()->json([ 'success' => false, 'message' => '未授权访问,请先登录', 'code' => 401, 'data' => null ], 401); } ```