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

时间:2016-04-01 22:24:33

标签: php json rest laravel

我正在尝试使用Laravel Framework构建REST api,我想要一种强制API始终使用JSON进行响应的方法,而不是通过这样做:

return Response::json($data);

换句话说,我希望每个响应都是JSON。有没有办法做到这一点?

  

更新:即使未找到异常,响应也必须是JSON   异常。

6 个答案:

答案 0 :(得分: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);
}

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

但是,如果出现任何错误,它将返回JSON响应。

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

答案 1 :(得分:2)

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;
    }
}

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.
        ],
]

现在,我们将仅在JSON中收到每个答复。

注意:异常也是如此

答案 2 :(得分:1)

按照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);
    }
}

将其添加到$routeMiddleware文件中的app/Http/Kernel.php

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

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

Route::group(['middleware' => ['json.response']], function () { ... });

答案 3 :(得分:1)

我使用了这里也提到的几种混合解决方案,以解决所有问题。原因是这里总是在“ / api”下面的每个请求上回复一个json响应。

  1. 创建一个中间件以强制在app/Http/Middleware/ForceJsonResponse.php中进行JSON输出
<?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);
    }
}

  1. 将此新的中间件添加到app/Http/Kernel.php的api数组的 TOP
    protected $middlewareGroups = [
        ...

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

        ...
    ];

  1. 覆盖Exception处理程序的呈现方法,该方法的所有异常也都以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);
+    }

}

答案 4 :(得分:0)

我知道已经回答了这个问题,但是这些不是很好的解决方案,因为它们以无法预测的方式更改状态代码。最好的解决方案是添加适当的标头,以使Laravel返回JSON(我认为是Accept: application/json),或者按照此出色的教程来始终告诉Laravel返回JSON:https://hackernoon.com/always-return-json-with-laravel-api-870c46c5efb2

如果您想更具选择性或适应更复杂的解决方案,也可以通过中间件来实现。

答案 5 :(得分:0)

您可以创建 After Middleware 并更改所有回复的结构

中间件:

'ir.ui.menu'

此中间件将强制响应内容类似

angular.json