猫でもわかるWebプログラミングと副業

本業エンジニアリングマネージャー。副業Webエンジニア。Web開発のヒントや、副業、日常生活のことを書きます。

【Laravel】ServerError のレスポンスを Json で返すために Handler に実装を見る

f:id:yoshiki_utakata:20210510220646p:plain

Laravel は、デフォルトで例外をキャッチして、サーバーエラーの表示をしてくれる。

この処理を行っているのは、 App\Exceptions\Handler である。

このクラスは Illuminate\Foundation\Exceptions\Handler を継承して作られており、メインの処理を行っているのは Illuminate\Foundation\Exceptions\Handler の方である。

Illuminate\Foundation\Exceptions\Handler を継承して拡張することで、様々なエラーレスポンスを返すことができます。

なお、デフォルトだと、 bootstrap/app.php において

<?php

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

という設定があります。

Handler の処理を見ていく

Illuminate\Foundation\Exceptions\Handler::render が、実際にエラーメッセージを表示するロジックである。

<?php

    public function render($request, Throwable $e)
    {
        if (method_exists($e, 'render') && $response = $e->render($request)) {
            return Router::toResponse($request, $response);
        } elseif ($e instanceof Responsable) {
            return $e->toResponse($request);
        }

        $e = $this->prepareException($e);

        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof AuthenticationException) {
            return $this->unauthenticated($request, $e);
        } elseif ($e instanceof ValidationException) {
            return $this->convertValidationExceptionToResponse($e, $request);
        }

        return $request->expectsJson()
                    ? $this->prepareJsonResponse($request, $e)
                    : $this->prepareResponse($request, $e);
    }

最初の部分

<?php

        if (method_exists($e, 'render') && $response = $e->render($request)) {
            return Router::toResponse($request, $response);
        } elseif ($e instanceof Responsable) {
            return $e->toResponse($request);
        }

もし、投げられた例外に render メソッドがあったり、 Responsable インタフェースが実装されていたら、そのメソッドを読んで結果を表示します。

次の部分

<?php

        $e = $this->prepareException($e);

        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof AuthenticationException) {
            return $this->unauthenticated($request, $e);
        } elseif ($e instanceof ValidationException) {
            return $this->convertValidationExceptionToResponse($e, $request);
        }

この部分は、一部例外については、それに対応したエラーを表示する対応になります。

最後の部分

<?php

        return $request->expectsJson()
                    ? $this->prepareJsonResponse($request, $e)
                    : $this->prepareResponse($request, $e);

これは、これまで処理してきた例外以外の例外の場合に適用される処理です。

エラーメッセージを、 Json または HTML で表示します。

$request->expectsJson()

$request->expectsJson() が true の場合、エラーレスポンスは Json 形式で返されることになります。

例えば、 Accept ヘッダーで、レスポンス形式 application/json などを要求している場合は、レスポンスが自動的に Json に変換されます。

他にも、ヘッダに X-Requested-With: XMLHttpRequest が指定されていると、ajax によるリクエストとみなされ、 Json のレスポンスを返すようになっています。

ヘッダに X-PJAX が指定されていて、 Accept ヘッダが指定されていない場合、pjax リクエストとみなされて、Json のレスポンスを返すようになっています。