開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Laravel >
  5. [Laravel] JSONレスポンスのUnicodeエスケープ無効化はミドルウェアで!
[Laravel] JSONレスポンスのUnicodeエスケープ無効化はミドルウェアで!

[Laravel] JSONレスポンスのUnicodeエスケープ無効化はミドルウェアで!

こんにちは、ナカエです。Unityの記事を書こうと思っていたのですがネタを見つけてしまったので今回もLaravelについての記事です。

PHPユーザーズ(日本語)の#laravelチャンネルのログで  
  • JSONレスポンスをブラウザで確認するときにUnicodeエスケープされているので解除したい
  • いちいち個別にJSON_UNESCAPED_UNICODEオプションを指定してまわるのは避けたい
  • LaravelのJsonResponse生成が直でnewされていたりするのでフレームワークの該当箇所を全て差し替えるのも辛い
という会話を見つけました。ブラウザ以外のツールを使ってレスポンスを確認するという解決策のほか、フレームワークの各所の依存を差し替えることでなんとかするという解決策が挙げられていました。 後者の知見がこちらの記事にまとまっています。

Laravelのjson応答でユニコードのエスケープをやめさせる

マルチバイト圏特有の問題なので英語圏では気にならないんでしょうね。別の解決方法のアイデアとその簡易実装について書きたいと思います。
 

HTTP周りの共通処理はミドルウェア

PSR-15厨なのでミドルウェアで解決します。HTTPレスポンスに関わる共通処理の置き所といえばミドルウェアです。
今回要求されるロジックは"アンエスケープが設定されていないJsonResponseをアンエスケープされたものに差し替える"。とても単純ですね。

ミドルウェアの実装は例えば下記のようになります。

<?php

namespace App\Http\Middleware;

use Symfony\Component\HttpFoundation\JsonResponse;

class UnescapeJsonResponse
{
    /**
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle($request, \Closure $next)
    {
        $response = $next($request);

        // JSON以外はそのまま
        if (!$response instanceof JsonResponse) {
            return $response;
        }

        // エンコードオプションを追加して設定し直す
        $newEncodingOptions = $response->getEncodingOptions() | JSON_UNESCAPED_UNICODE;
        $response->setEncodingOptions($newEncodingOptions);

        return $response;
    }
}

解説

実装にあたって、IlluminateのJsonResponseの継承元であるSymfony\Component\HttpFoundation\JsonResponseを調べました。流石は天下のSymfonyのhttp-foundation、今回の処理を9割方を解決してくれるメソッドがあります。こちらのgetterとsetterの2つがあれば、あとはエンコードオプションにビット和でJSON_UNESCAPED_UNICODEを追加するのみです。

<php
namespace Symfony\Component\HttpFoundation;

class JsonResponse extends Response
{
    /**
     * Returns options used while encoding data to JSON.
     *
     * @return int
     */
    public function getEncodingOptions()
    {
        return $this->encodingOptions;
    }

    /**
     * Sets options used while encoding data to JSON.
     *
     * @param int $encodingOptions
     *
     * @return $this
     */
    public function setEncodingOptions($encodingOptions)
    {
        $this->encodingOptions = (int) $encodingOptions;

        return $this->setData(json_decode($this->data));
    }
}

使い方

Kernelに上記ミドルウェアを追加するのみです。JSONレスポンス以外はそのまま素通しします。

スクリーンショット 2018-07-20 12.46.25.png
実用上は、デバッグモード時のみこのミドルウェアを有効にするなど少し改良が必要でしょう。

TOPに戻る