如何在Lumen中捕获AfterMiddleware中的异常?

时间:2017-05-23 09:27:42

标签: exception exception-handling lumen laravel-middleware

Lumen 5.4。

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        try {
            return $next($request);
        } catch (IpValidationException $e) {
            return response()->json($e->getMessage(), 422);
        } catch (RemoteException $e) {
            return response()->json($e->getMessage(), 503);
        } catch (BaseException $e) {
            return response()->json($e->getMessage(), 400);
        } catch (\Exception $e) {
            return response()->json($e->getMessage(), $e->getCode());
        }
    }
}

引发异常后,$next($request)转到Laravel\Lumen\Routing中的以下函数:

/**
 * Get the initial slice to begin the stack call.
 *
 * @param  \Closure  $destination
 * @return \Closure
 */
protected function prepareDestination(BaseClosure $destination)
{
    return function ($passable) use ($destination) {
        try {
            return call_user_func($destination, $passable);
        } catch (Exception $e) {
            return $this->handleException($passable, $e);
        } catch (Throwable $e) {
            return $this->handleException($passable, new FatalThrowableError($e));
        }
    };
}

它被抓到那里,所以我AfterMiddleware没用。任何想法如何绕过它?我找到了一个解决方案,并将所有例外情况移到render()类的Handler中,但使用中间件更方便。

2 个答案:

答案 0 :(得分:1)

我还没试过这个,但是从Lumen的代码来看,我认为这是可能的。

handleException调用的prepareDestination函数检查ExceptionHanlder是否绑定到容器。如果不是,则抛出异常。

protected function handleException($passable, Exception $e)
    {
        if (! $this->container->bound(ExceptionHandler::class) || ! $passable instanceof Request) {
            throw $e;
        }

        $handler = $this->container->make(ExceptionHandler::class);

        $handler->report($e);

        return $handler->render($passable, $e);
    }

因此,请尝试从bootstrap/app.php

中删除以下ExceptionHandler绑定
$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

答案 1 :(得分:-1)

这就是我处理我的方法,它处理Lumen 5.5。*和php 7.1。

迟到的答案,但希望它能帮助别人。

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Http\Exception\HttpResponseException;
use Symfony\Component\Debug\Exception\FatalThrowableError;


class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that should not be reported.
     *
     * @var array
     */
    protected $dontReport = [
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        ValidationException::class,
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception  $e
     * @return void
     */
    public function report(Exception $e)
    {
        parent::report($e);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $e)
    {
        // if (env('APP_DEBUG')) {
        //     return parent::render($request, $e);
        // }
        $response = [
            'success' => false
        ];
        $response['status']   = null;

        if ($e instanceof HttpResponseException) {
            $response['status']   = Response::HTTP_INTERNAL_SERVER_ERROR;
        } elseif ($e instanceof MethodNotAllowedHttpException) {
            $response['status'] = Response::HTTP_METHOD_NOT_ALLOWED;
        } elseif ($e instanceof NotFoundHttpException) {
            $response['status'] = Response::HTTP_NOT_FOUND;
        } elseif ($e instanceof AuthorizationException) {
            $response['status'] = Response::HTTP_FORBIDDEN;
            $e      = new AuthorizationException('HTTP_FORBIDDEN', $response['status']);
        } elseif ($e instanceof ValidationException && $e->getResponse()) {
            $response['status']   = Response::HTTP_BAD_REQUEST;
            $e        = new ValidationException('HTTP_BAD_REQUEST', $response['status'], $e);
        } elseif ($e instanceof ValidationException) {
            $response['status']   = 422;
            $response['errors'] = $e->validator->errors();
        } elseif ($e instanceof ModelNotFoundException) {
          $response['status'] = 404;
        } elseif ($e instanceof UnableToExecuteRequestException) {
            $response['status'] = $e->getCode();
        } elseif ($e instanceof FatalThrowableError) {
            $response['status'] = Response::HTTP_INTERNAL_SERVER_ERROR;
        } elseif ($e) {
            $response['status'] = Response::HTTP_INTERNAL_SERVER_ERROR;
            $response['unhandled'] = 'exception-lumen-ksoft';
        }

        if ($response['status']) {
            $response['message'] = $e->getMessage();
            $response['error_code'] = $e->getCode() ?? '';
            // $response['exception'] = $e->getTraceAsString() ?? '';
            if (app()->environment() == 'local'){
                $response['file'] = $e->getFile() ?? '';
                $response['line'] = $e->getLine() ?? '';
            }
            return response()->json($response, $response['status']);
        } else {
            return parent::render($request, $e);
        }

    }
}