Laravel控制器方法统一异常处理:模拟Python装饰器实现问询
在Laravel中实现控制器方法的异常捕获"装饰器"
PHP确实没有Python那种原生@装饰器语法,但Laravel有好几招能实现类似效果,不用在每个控制器方法里重复写try-catch:
方法一:用路由中间件搞定
搞个中间件,专门抓指定路由或方法的异常,返回统一格式:
- 先创建中间件
php artisan make:middleware CatchMethodExceptions
- 写中间件核心逻辑
打开app/Http/Middleware/CatchMethodExceptions.php,把handle方法改成这样:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Response; use Throwable; class CatchMethodExceptions { public function handle($request, Closure $next) { try { return $next($request); } catch (Throwable $e) { // 自定义你要返回的结构 return response()->json([ 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, 'message' => '服务器内部错误', 'error' => env('APP_DEBUG') ? $e->getMessage() : '' ], Response::HTTP_INTERNAL_SERVER_ERROR); } } }
- 注册中间件
去app/Http/Kernel.php的$routeMiddleware数组里加一行:
'catch.exceptions' => \App\Http\Middleware\CatchMethodExceptions::class,
- 给目标路由/方法绑中间件
- 单个路由绑定:
Route::get('/user/{id}', [UserController::class, 'show'])->middleware('catch.exceptions');
- 控制器内只给特定方法加:
在控制器的__construct里指定就行:
public function __construct() { // 只给show和store方法加 $this->middleware('catch.exceptions')->only(['show', 'store']); // 要是想排除某些方法就用->except(['index']) }
方法二:用Trait复用捕获逻辑
要是只想给某几个控制器的特定方法加,整个Trait最方便:
- 创建Trait文件
在app/Traits目录下建个CatchExceptions.php:
<?php namespace App\Traits; use Illuminate\Http\Response; use Throwable; trait CatchExceptions { protected function catchExceptions(callable $callback) { try { return $callback(); } catch (Throwable $e) { return response()->json([ 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, 'message' => '操作失败', 'error' => env('APP_DEBUG') ? $e->getMessage() : '' ], Response::HTTP_INTERNAL_SERVER_ERROR); } } }
- 在控制器里用
<?php namespace App\Http\Controllers; use App\Traits\CatchExceptions; use Illuminate\Http\Request; class UserController extends Controller { use CatchExceptions; public function show($id) { return $this->catchExceptions(function () use ($id) { // 原来的方法逻辑,比如查用户 $user = User::findOrFail($id); return response()->json(['data' => $user]); }); } }
方法三:全局异常处理(批量搞定)
要是想所有控制器的异常都统一返回格式,改Laravel自带的异常处理器就行:
打开app/Exceptions/Handler.php,修改render方法:
<?php namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Http\Response; use Throwable; class Handler extends ExceptionHandler { // ... 保留原来的其他代码 public function render($request, Throwable $e) { // 只给API请求返回统一格式 if ($request->expectsJson()) { $code = $this->isHttpException($e) ? $e->getStatusCode() : Response::HTTP_INTERNAL_SERVER_ERROR; $message = $this->isHttpException($e) ? $e->getMessage() : '服务器内部错误'; return response()->json([ 'code' => $code, 'message' => $message, 'error' => env('APP_DEBUG') ? $e->getMessage() : '' ], $code); } return parent::render($request, $e); } }
这种方式适合全局统一处理,不用逐个方法加;要是需要针对部分方法特殊处理,结合前两种方式更灵活。
内容的提问来源于stack exchange,提问作者Danilo Toro
相关产品推荐
相关产品推荐

