你如何对Laravel中的每个响应强制执行JSON响应?

Mus*_*kat 8 php rest json laravel

我正在尝试使用Laravel Framework构建一个REST api,我想要一种方法来强制API始终使用JSON进行响应,而不是通过以下方式执行此操作:

return Response::json($data);
Run Code Online (Sandbox Code Playgroud)

换句话说,我希望每个响应都是JSON.有没有一个好方法呢?

更新:即使在未找到异常的异常情况下,响应也必须是JSON.

M16*_*437 24

按照Alexander Lichter 的建议创建一个中间件,为Accept每个请求设置标头:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class ForceJsonResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        $request->headers->set('Accept', 'application/json');

        return $next($request);
    }
}
Run Code Online (Sandbox Code Playgroud)

将它添加到$routeMiddleware了在app/Http/Kernel.php文件中:

protected $routeMiddleware = [
    (...)
    'json.response' => \App\Http\Middleware\ForceJsonResponse::class,
];
Run Code Online (Sandbox Code Playgroud)

您现在可以包装所有应返回 JSON 的路由:

Route::group(['middleware' => ['json.response']], function () { ... });
Run Code Online (Sandbox Code Playgroud)

编辑:对于 Laravel 6.9+

json.response中间件优先于其他中间件 -Authorize在设置Accept标头之前处理请求被其他中间件(例如中间件)终止的情况。

为此 - 用以下方法覆盖App\Http\Kernel类 ( app/Http/Kernel.php)的构造函数:

    public function __construct( Application $app, Router $router ) {
        parent::__construct( $app, $router );
        $this->prependToMiddlewarePriority(\App\Http\Middleware\ForceJsonResponse::class);
    }
Run Code Online (Sandbox Code Playgroud)


Jon*_*oso 9

我知道这已得到解答,但这些都不是好的解决方案,因为它们以不可预测的方式更改状态代码。最好的解决方案是添加适当的标头,以便 Laravel 返回 JSON(我认为是它Accept: application/json),或者按照这个很棒的教程总是告诉 Laravel 返回 JSON:https ://hackernoon.com/always-return-json-with -laravel-api-870c46c5efb2

如果您想要更有选择性或适应更复杂的解决方案,您也可以通过中间件来做到这一点。


小智 9

我使用了这里提到的几种混合解决方案来解决所有问题,使其更加动态。原因是总是用 json 响应回复“/api”下面的每个请求。

  1. 创建一个中间件以强制 JSON 输出app/Http/Middleware/ForceJsonResponse.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class ForceJsonResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // set Accept request header to application/json
        $request->headers->set('Accept', 'application/json');

        return $next($request);
    }
}

Run Code Online (Sandbox Code Playgroud)
  1. 将这个新的中间件添加到api 数组的顶部app/Http/Kernel.php
    protected $middlewareGroups = [
        ...

        'api' => [
            \App\Http\Middleware\ForceJsonResponse::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        ...
    ];

Run Code Online (Sandbox Code Playgroud)
  1. 覆盖异常处理程序的 render 方法,所有异常也以 JSON 响应app/Exceptions/Handler.php
  namespace App\Exceptions;

  use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+ use Throwable;

  class Handler extends ExceptionHandler
  {

     ...


+    /**
+     * Render an exception into an HTTP response.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Throwable $e
+     * @return \Illuminate\Http\Response
+     */
+    public function render($request, Throwable $e)
+    {
+        // Force to application/json rendering on API calls
+        if ($request->is('api*')) {
+            // set Accept request header to application/json
+            $request->headers->set('Accept', 'application/json');
+        }
+
+        // Default to the parent class' implementation of handler
+        return parent::render($request, $e);
+    }

}
Run Code Online (Sandbox Code Playgroud)


Dip*_*mar 7

Laravel 中间件在这个用例中非常有用。

1.制作JsonResponseMiddleware中间件。

php artisan make:middleware JsonResponseMiddleware


namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\ResponseFactory;

class JsonResponseMiddleware
{
    /**
     * @var ResponseFactory
     */
    protected $responseFactory;

    /**
     * JsonResponseMiddleware constructor.
     */
    public function __construct(ResponseFactory $responseFactory)
    {
        $this->responseFactory = $responseFactory;
    }

    /**
     * Handle an incoming request.
     *
     * @param Request $request
     * @param Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // First, set the header so any other middleware knows we're
        // dealing with a should-be JSON response.
        $request->headers->set('Accept', 'application/json');

        // Get the response
        $response = $next($request);

        // If the response is not strictly a JsonResponse, we make it
        if (!$response instanceof JsonResponse) {
            $response = $this->responseFactory->json(
                $response->content(),
                $response->status(),
                $response->headers->all()
            );
        }

        return $response;
    }
}
Run Code Online (Sandbox Code Playgroud)

2.注册中间件 App\Http\Kernel.php

protected $middlewareGroups = [

        'api' => [
            ...
            ....
            /// Force to Json response (Our created Middleware)
            \App\Http\Middleware\JsonResponseMiddleware::class,
        ],


        'web' => [
            ...
            ....
            /// Add Here as well if we want to force response in web routes too.
        ],
]
Run Code Online (Sandbox Code Playgroud)

现在我们将JSON只收到每个响应。

请注意:即使是异常也会以 JSON 格式响应

  • 使用中间件是比从构造函数返回响应更好的方法。谢谢亲爱的。你的解决方案对我有用。 (2认同)
  • 我认为“JsonResponse”实例中的某些方法已被重命名。例如 `$response-&gt;content()` 现在是 `$response-&gt;getContent()` 并且 `$response-&gt;status()` 现在是 `$response-&gt;getStatusCode()` (2认同)

Duc*_*her 5

JSON在控制器中返回return $data;

有关JSON错误的响应,请转到app\Exceptions\Handler.php文件并查看render方法.

你应该能够重写它看起来像这样:

public function render($request, Exception $e)
{
    // turn $e into an array.
    // this is sending status code of 500
    // get headers from $request.
    return response()->json($e, 500);
}
Run Code Online (Sandbox Code Playgroud)

但是你必须决定如何处理$e,因为它需要是一个array.您还可以设置状态代码和标题数组.

但是在任何错误的情况下,它都会返回JSON响应.

编辑:还可以注意到,您可以更改report方法以处理laravel如何记录错误.更多信息在这里.