Laravel Dingo Api - 如何从 API 控制器返回 JSON 格式的错误响应?

Posted

技术标签:

【中文标题】Laravel Dingo Api - 如何从 API 控制器返回 JSON 格式的错误响应?【英文标题】:Laravel Dingo Api - How to return JSON formatted error response from API Controller? 【发布时间】:2014-08-24 23:16:38 【问题描述】:

在我的 routes.php 中,我有这个:

$apiSettings = [
    'version' => 'v1',
    'prefix' => 'api',
    'protected' => true
];   
Route::api($apiSettings, function() 
    Route::get('venue', 'ApiDataController@venue');
);

受保护的场地 API 路由访问控制器方法。控制器方法在 Venues 模型上执行 Eloquent Query,并返回响应。这完美地工作。 如果我想返回错误,问题就出在 - 我不确定如何。这是场地方法:

public function venue()

    try 
        //Some code that returns an exception
     catch(someexception $e) 
        //How do I return the exception such that Dingo will parse it into a proper JSON response?
    
    $response = Venue::with('address')->get();
    return $response;


我尝试的解决方案(在 try 块中):

try 
    //some code that returns an exception
 catch(someexception $e) 
    $response = array(
        'message' => 'some random exception message'
    );
    return Response::json($response, 403);

当我尝试这样做时出现以下错误: Argument 1 passed to Dingo\Api\Http\Response::makeFromExisting() must be an instance of Illuminate\Http\Response, instance of Illuminate\Http\JsonResponse given, called in /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php on line 165 and defined

第二次尝试的解决方案: 从 Dingo 的 Returning Errors 文档中,我测试了如果我返回异常之一会发生什么:

public function venue()
    throw new Symfony\Component\HttpKernel\Exception\ConflictHttpException('err);

但是,不是将错误作为 JSON 响应返回,而是出现 laravel 错误页面,并显示以下错误:

【内部函数】:ApiDataController->venue() #1 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(231): call_user_func_array(数组,数组) #2 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(93): Illuminate\Routing\Controller->callAction('venue', Array) #3 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(62): Illuminate\Routing\ControllerDispatcher->call(Object(ApiDataController), 对象(照亮\路由\路由),“地点”) #4 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(930): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), 对象(Dingo\Api\Http\InternalRequest),'ApiDataControll...','地点') #5【内部函数】:Illuminate\Routing\Router->Illuminate\Routing\closure() #6 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(105): call_user_func_array(对象(闭包),数组) #7 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(996): Illuminate\Routing\Route->run(Object(Dingo\Api\Http\InternalRequest)) #8 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(964): Illuminate\Routing\Router->dispatchToRoute(Object(Dingo\Api\Http\InternalRequest)) #9 /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php(147): Illuminate\Routing\Router->dispatch(Object(Dingo\Api\Http\InternalRequest)) #10 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(337): Dingo\Api\Routing\Router->dispatch(Object(Dingo\Api\Http\InternalRequest)) #11 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(278): Dingo\Api\Dispatcher->dispatch(Object(Dingo\Api\Http\InternalRequest)) #12 /vagrant/www/planat-app/vendor/dingo/api/src/Dispatcher.php(213): Dingo\Api\Dispatcher->queueRequest('get', 'venue', Array) #13 /vagrant/www/planat-app/app/routes.php(51): Dingo\Api\Dispatcher->get('venue') #14 [内部函数]: closure() #15 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(105): call_user_func_array(对象(闭包),数组) #16 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(996): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request)) #17 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(964): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request)) #18 /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php(147): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request)) #19 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(738): Dingo\Api\Routing\Router->dispatch(Object(Illuminate\Http\Request)) #20 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(708): Illuminate\Foundation\Application->dispatch(Object(Illuminate\Http\Request)) #21 /vagrant/www/planat-app/vendor/dingo/api/src/Http/Middleware/RateLimit.php(97): Illuminate\Foundation\Application->handle(Object(Illuminate\Http\Request), 1、真) #22 /vagrant/www/planat-app/vendor/dingo/api/src/Http/Middleware/Authentication.php(102): Dingo\Api\Http\Middleware\RateLimit->handle(Object(Illuminate\Http\Request), 1、真) #23 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Session/Middleware.php(72): Dingo\Api\Http\Middleware\Authentication->handle(Object(Illuminate\Http\Request), 1、真) #24 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Cookie/Queue.php(47): Illuminate\Session\Middleware->handle(Object(Illuminate\Http\Request), 1、真) #25 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Cookie/Guard.php(51): Illuminate\Cookie\Queue->handle(Object(Illuminate\Http\Request), 1, 真的) #26 /vagrant/www/planat-app/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Illuminate\Cookie\Guard->handle(Object(Illuminate\Http\Request), 1, 真的) #27 /vagrant/www/planat-app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(606): Stack\StackedHttpKernel->handle(对象(Illuminate\Http\Request)) #28 /vagrant/www/planat-app/public/index.php(49): Illuminate\Foundation\Application->run()

【问题讨论】:

在 laravel 错误页面中,是否显示相同的“传递给 Dingo\Api\Http\Response::makeFromExisting() 的参数 1 必须是 Illuminate\Http\Response 的实例”或什么它显示?我认为它现在应该显示一个不同的错误更可复制粘贴的错误消息也应该是您的app/storage/logs/laravel.log 中的最后一个块。 我已经用 laravel.log 中的堆栈跟踪更新了问题 我认为这与语法错误有关。你能检查你的控制器动作有正确的大括号和一切吗?或在此处发布您的控制器操作代码。 如果你能得到[internal function]:上方两行的错误日志,那就太好了 @Unnawut 为什么您需要尝试捕获然后响应异常消息。 Dingo 将处理异常并自动响应异常消息。请参阅以下示例。 "message": "Undefined variable: x", "status_code": 500 Api 端点有一个未定义的变量 "x" 并且 dingo 适当地处理它 【参考方案1】:

阅读 Dingo 的 Returning Errors 文档,它说:

您可以简单地抛出异常,包将处理异常并返回适当的响应,而不是手动创建和返回错误响应。

以下是遇到错误时应抛出的所有受支持异常的列表。

Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException Symfony\Component\HttpKernel\Exception\BadRequestHttpException Symfony\Component\HttpKernel\Exception\ConflictHttpException Symfony\Component\HttpKernel\Exception\GoneHttpException Symfony\Component\HttpKernel\Exception\HttpException Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException Symfony\Component\HttpKernel\Exception\NotFoundHttpException Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException

它还支持一些通用资源异常,您也可以将验证错误传递给它们:

Dingo\Api\Exception\DeleteResourceFailedException Dingo\Api\Exception\ResourceException Dingo\Api\Exception\StoreResourceFailedException Dingo\Api\Exception\UpdateResourceFailedException

因此,简而言之,您需要将 Dingo 支持的上述异常之一抛出回 Dingo。例如:

try 
    //Some code that returns an exception
 catch(SomeException $e) 
    throw new Symfony\Component\HttpKernel\Exception\HttpException($e->getMessage);

或者事实上,如果抛出的异常是上述类型之一,或者是扩展它们的类型,你可以完全删除你的 try/catch 子句。异常应该会自动抛出给 Dingo 处理。

【讨论】:

您好 Unnawut,感谢您的回答。但是,我最初确实尝试过,但我得到了一个例外:传递给 Dingo\Api\Http\Response::makeFromExisting() 的参数 1 必须是 Illuminate\Http\Response 的实例,Illuminate\Http\JsonResponse 的实例给定,在第 165 行的 /vagrant/www/planat-app/vendor/dingo/api/src/Routing/Router.php 中调用并定义 我已更新问题以包含我尝试的解决方案(与您提供的相同)以及我得到的错误响应。 @Muserk 我原来的答案完全是错误的。更新了! 感谢您的回答。但是,当我抛出他们指定的任何异常时,它不会以 JSON 形式返回。相反,出现了 laravel 错误页面,并带有异常消息。 您能否也将您的最新代码附加到问题中?以防其他人有想法。【参考方案2】:

在构建 api 时,您可以全局捕获类似类型的异常。例如,如果用户尝试使用不存在的 ID 获取客户,那么您可以这样做。

Customer::findOrFail($id);

那么你可以像这样在app/start/global.php 中捕获所有这种类型的异常。

App::error(function(ModelNotFoundException $modelNotFoundException)
    $errorResponse = [
        'errors'    => 'Not found any resource',
        'message'   => $modelNotFoundException->getMessage()
    ];

    return Response::json($errorResponse, 404);     //404 = Not found
);

【讨论】:

【参考方案3】:

请检查:

try 
    //some code that returns an exception
 catch(\Exception $e) 
    $response = array(
        'message' => 'some random exception message'
    );
    return response()->json($response, 403);

请检查并告诉我。

【讨论】:

以上是关于Laravel Dingo Api - 如何从 API 控制器返回 JSON 格式的错误响应?的主要内容,如果未能解决你的问题,请参考以下文章

laravel/dingo API 上的变压器使用

Laravel 5.4+ Dingo +Jwt 快速搭建 API系统

laravel dingo/api添加jwt-auth认证

php 使用Laravel Nova API防止Dingo API冲突

Laravel Dingo API 和中间件问题\\VerifyCsrfToken.php

您的要求无法解析为一组可安装的软件包Dingo / api未安装在laravel v5.5.24上