Laravel 5:请求JSON时处理异常

Jon*_*hon 37 php ajax exception csrf laravel

我正在通过Laravel 5上的AJAX上传文件.除了一件事,我几乎所有工作都在工作.

当我尝试上传一个太大的文件时(比我更大upload_max_filesize,post_max_size我得到了一个TokenMismatchException).

但是,这是预料之中的,因为我知道如果超出这些限制,我的输入将为空.空输入,意味着没有_token收到,因此负责验证CSRF令牌的中间件为什么会大惊小怪.

然而,我的问题不是抛出这个异常,而是渲染它的方式.当Laravel捕获到这个异常时,它正在为通用的Whoops页面吐出HTML(由于我处于调试模式,因此加载了堆栈跟踪).

处理此异常的最佳方法是什么,以便通过AJAX返回JSON(或者在请求JSON时),同时保持默认行为?


编辑:无论抛出什么异常,这似乎都会发生.我刚尝试通过AJAX(数据类型:JSON)向一个"页面"发出请求,该页面在尝试获取404时不存在,同样的事情发生 - 返回HTML,没有JSON友好.

Jon*_*hon 85

考虑到@Wader给出的答案以及@Tyler Crompton的评论,我打算自己动手拍这个:

应用程序/异常/ Handler.php

/**
 * 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 the request wants JSON (AJAX doesn't always want JSON)
    if ($request->wantsJson()) {
        // Define the response
        $response = [
            'errors' => 'Sorry, something went wrong.'
        ];

        // If the app is in debug mode
        if (config('app.debug')) {
            // Add the exception class name, message and stack trace to response
            $response['exception'] = get_class($e); // Reflection might be better here
            $response['message'] = $e->getMessage();
            $response['trace'] = $e->getTrace();
        }

        // Default response of 400
        $status = 400;

        // If this exception is an instance of HttpException
        if ($this->isHttpException($e)) {
            // Grab the HTTP status code from the Exception
            $status = $e->getStatusCode();
        }

        // Return a JSON response with the response array and status code
        return response()->json($response, $status);
    }

    // Default to the parent class' implementation of handler
    return parent::render($request, $e);
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以将行设置状态代码缩短为:`$ status = method_exists($ e,'getStatusCode')?$ e-> getStatusCode():400;` (2认同)

Wad*_*der 11

在你的应用程序中你应该有app/Http/Middleware/VerifyCsrfToken.php.在该文件中,您可以处理中间件的运行方式.所以你可以检查请求是否是ajax并处理你喜欢的方式.

另外,也许是一个更好的解决方案,就是编辑异常处理程序以返回json.看app/exceptions/Handler.php,像下面这样的东西将是一个起点

public function render($request, Exception $e)
{
    if ($request->ajax() || $request->wantsJson())
    {
        $json = [
            'success' => false,
            'error' => [
                'code' => $e->getCode(),
                'message' => $e->getMessage(),
            ],
        ];

        return response()->json($json, 400);
    }

    return parent::render($request, $e);
}
Run Code Online (Sandbox Code Playgroud)


小智 8

在@ Jonathon的处理程序渲染功能的基础上,我只想修改条件以排除ValidationException实例.

// If the request wants JSON + exception is not ValidationException
if ($request->wantsJson() && ( ! $exception instanceof ValidationException))
Run Code Online (Sandbox Code Playgroud)

如果合适,Laravel 5已经在JSON中返回验证错误.

App/Exceptions/Handler.php中的完整方法:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)
{
    // If the request wants JSON + exception is not ValidationException
    if ($request->wantsJson() && ( ! $exception instanceof ValidationException))
    {
        // Define the response
        $response = [
            'errors' => 'Sorry, something went wrong.'
        ];

        // If the app is in debug mode
        if (config('app.debug'))
        {
            // Add the exception class name, message and stack trace to response
            $response['exception'] = get_class($exception); // Reflection might be better here
            $response['message'] = $exception->getMessage();
            $response['trace'] = $exception->getTrace();
        }

        // Default response of 400
        $status = 400;

        // If this exception is an instance of HttpException
        if ($this->isHttpException($exception))
        {
            // Grab the HTTP status code from the Exception
            $status = $exception->getCode();
        }

        // Return a JSON response with the response array and status code
        return response()->json($response, $status);
    }
    return parent::render($request, $exception);
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*amo 6

我已经改变了几个在Laravel 5.3上工作的实现.主要的区别是我的将返回正确的HTTP状态文本

在app\Exceptions\Handler.php中的render()函数中,将此代码段添加到顶部:

    if ($request->wantsJson()) {
        return $this->renderExceptionAsJson($request, $exception);
    }
Run Code Online (Sandbox Code Playgroud)

renderExceptionAsJson的内容:

/**
 * Render an exception into a JSON response
 *
 * @param $request
 * @param Exception $exception
 * @return SymfonyResponse
 */
protected function renderExceptionAsJson($request, Exception $exception)
{
    // Currently converts AuthorizationException to 403 HttpException
    // and ModelNotFoundException to 404 NotFoundHttpException
    $exception = $this->prepareException($exception);
    // Default response
    $response = [
        'error' => 'Sorry, something went wrong.'
    ];

    // Add debug info if app is in debug mode
    if (config('app.debug')) {
        // Add the exception class name, message and stack trace to response
        $response['exception'] = get_class($exception); // Reflection might be better here
        $response['message'] = $exception->getMessage();
        $response['trace'] = $exception->getTrace();
    }

    $status = 400;
    // Build correct status codes and status texts
    switch ($exception) {
        case $exception instanceof ValidationException:
            return $this->convertValidationExceptionToResponse($exception, $request);
        case $exception instanceof AuthenticationException:
            $status = 401;
            $response['error'] = Response::$statusTexts[$status];
            break;
        case $this->isHttpException($exception):
            $status = $exception->getStatusCode();
            $response['error'] = Response::$statusTexts[$status];
            break;
        default:
            break;
    }

    return response()->json($response, $status);
}
Run Code Online (Sandbox Code Playgroud)


Gra*_* S. 5

在 Laravel 8.x 中,你可以这样做

应用程序/Http/Exceptions/Handler.php

public function render($request, Throwable $exception)
{
    if ($request->wantsJson()) {
        return parent::prepareJsonResponse($request, $exception);
    }

    return parent::render($request, $exception);
}
Run Code Online (Sandbox Code Playgroud)

如果您希望始终为所有异常返回 JSON,只需始终调用parent::prepareJsonResponse并删除即可parent::render

当使用 呈现 JSON 时APP_DEBUG=true,您将获得完整的错误报告和堆栈跟踪。当 时APP_DEBUG=false,您将收到一条通用消息,这样您就不会意外暴露应用程序详细信息。