Laravel8异常返回自定义json

相关环境:PHP7.4 + Laravel8.83.8
背景:本人是前后端分离的情况,最近和前端同学调接口,当遇到异常:比如Exception的异常。运行接口地址是一个页面类型错误(如下图):

但是经理并不想以页面的方式给用户看,认为不太妥当,他要求:和正常接口返回一样以json数据方式返回给前端,前端提示相关错误。

比如我模拟异常,在控制器写了这行代码:

<?php

namespace App\Http\Admin\User;

use App\Http\Admin\Controller;

class UserController extends Controller
{
    public function test()
    {
         throw new \Exception("出bug啦");
    }
}

那么laravel框架是支持这种做法的,具体步骤如下:
在app\Exceptions\Handler.php里面,有个render方法,他的作用就是:渲染异常为 HTTP 响应

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<Throwable>>
     */
    protected $dontReport = [
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->reportable(function (Throwable $e) {
            //
        });
    }

    public function render($request, Throwable $e)
    {
        return response()->json([
            'code' => $e->getCode() ?? 1,
            'file' => $e->getFile(), //获取出错误的文件
            'line' => $e->getLine(), //获取错误在哪一行
            'message' => $e->getMessage() ?? "error!",
            'data' => []
        ]);
    }
}

再次运行结果就是json:

{
    "code": 0,
    "file": "/home/vagrant/www/admin/app/Http/Admin/User/UserController.php",
    "line": 17,
    "message": "出bug啦",
    "data": []
}

可以再验证一下数据库方面的,比如查询的字段在表里根本没有,看看能不能返回json:
控制器代码:

<?php

namespace App\Http\Admin\User;

use App\Http\Admin\Controller;

class UserController extends Controller
{
    public function test()
    {
        //lmobile字段在表中没有
         UserAdmin::find(2, ['id', 'lmobile']);
    }
}

结果如下:

{
    "code": "42S22",
    "file": "/home/vagrant/www/admin/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
    "line": 712,
    "message": "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'lmobile' in 'field list' (SQL: select `id`, `lmobile` from `user_admin` where `user_admin`.`id` = 2 limit 1)",
    "data": []
}

同样的也能正常返回json格式。

如果你不想改动app\Exceptions\Handler.php还有一种方法:通过设置请求头的accept:
如果前端同学加了accept头为application/json

如果你当心前端同学忘记加这个,我们也可以在框架路由配置那边加:

<?php

use App\Http\Api\User\AgreementController;
use App\Http\Api\User\UserController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

if (!request()->headers->get('accept')) {
    request()->headers->set('accept', 'application/json');
}

Route::any("/user/test", [UserController::class, "test"]);

同样可以达到效果,当然你也可以采用中间件的方式,新建一个中间件,在handle方法里面第一句就写上$request->headers->set('accept', 'application/json');
然后把该中间件放到app\Http\Kernel.php的$middleware全局路由数组里面就可。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2
mowangjuanzi

请求的时候添加上 Accept: application/json 也可以

1个月前 评论
bluememory (楼主) 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!