Laravel Lumen确保JSON响应

时间:2016-05-18 10:17:24

标签: php json api laravel lumen

我是Laravel和Lumen的新手。我想确保我总是只获得一个JSON对象作为输出。我怎么能在流明做到这一点?

我可以使用response()->json($response);获取JSON响应。但是当发生错误时,API会给我text/html个错误。但我只想要application/json个回复。

提前致谢。

6 个答案:

答案 0 :(得分:29)

您需要调整异常处理程序(app/Exceptions/Handler.php)以返回所需的响应。

这是可以做什么的一个非常基本的例子。

public function render($request, Exception $e)
{
    $rendered = parent::render($request, $e);

    return response()->json([
        'error' => [
            'code' => $rendered->getStatusCode(),
            'message' => $e->getMessage(),
        ]
    ]);
}

答案 1 :(得分:5)

基于@Wader答案的更准确的解决方案可以是:

use Illuminate\Http\JsonResponse;

public function render($request, Exception $e)
{
    $parentRender = parent::render($request, $e);

    // if parent returns a JsonResponse 
    // for example in case of a ValidationException 
    if ($parentRender instanceof JsonResponse)
    {
        return $parentRender;
    }

    return new JsonResponse([
        'message' => $e instanceof HttpException
            ? $e->getMessage()
            : 'Server Error',
    ], $parentRender->status());
}

答案 2 :(得分:1)

我建议您添加一个附加了Accept中间件并将其设置为application/json的中间件,而不是触摸异常处理程序。

例如,您可以创建一个名为RequestsAcceptJson的中间件,并以此方式进行定义:

<?php

namespace App\Http\Middleware;

use Closure;

class RequestsAcceptJson
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $acceptHeader = strtolower($request->headers->get('accept'));

        // If the accept header is not set to application/json
        // We attach it and continue the request
        if ($acceptHeader !== 'application/json') {
            $request->headers->set('Accept', 'application/json');
        }

        return $next($request);
    }
}

然后,您只需要将其注册为全局中间件,即可在对api的每个请求中运行。在流明中,您可以通过在bootstrap/app.php

内的中间件调用中添加类来实现
$app->middleware([
    App\Http\Middleware\RequestsAcceptJson::class
]);

与Laravel几乎相同的过程。现在,错误处理程序将始终返回json而不是纯文本/ html。

答案 3 :(得分:0)

作为MTVS的答案,您甚至可以使用JsonResponse类来格式化响应,并将其用作render方法中的静态成员,而不是像这样将其导入Handler命名空间中:

public function render($request, Exception $e)
{
    $parentRender = parent::render($request, $e);

    // if parent returns a JsonResponse 
    // for example in case of a ValidationException 
    if ($parentRender instanceof \Illuminate\Http\JsonResponse)
    {
        return $parentRender;
    }

    return new \Illuminate\Http\JsonResponse([
        'message' => $e instanceof HttpException
            ? $e->getMessage()
            : 'Server Error',
    ], $parentRender->status());
}

答案 4 :(得分:0)

如果我正在使用API​​,我就是在这样做

<?php namespace App\Exceptions;

use Exception;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Http\Response;

class Handler extends ExceptionHandler
{
   /**
    * A list of the exception types that should not be reported.
    *
    * @var array
    */
  protected $dontReport = [
    AuthorizationException::class,
    HttpException::class,
    ModelNotFoundException::class,
    ValidationException::class,
  ];

/**
 * Report or log an exception.
 *
 * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
 *
 * @param Exception $e
 *
 * @throws Exception
 */
public function report(Exception $e): void
{
    parent::report($e);
}

/**
 * @param \Illuminate\Http\Request $request
 * @param Exception $e
 *
 * @return \Illuminate\Http\JsonResponse|Response
 */
public function render($request, Exception $e)
{
    if (env('APP_DEBUG')) {
        return parent::render($request, $e);
    }

    $status = Response::HTTP_INTERNAL_SERVER_ERROR;

    if ($e instanceof HttpResponseException) {
        $status = Response::HTTP_INTERNAL_SERVER_ERROR;
    } elseif ($e instanceof MethodNotAllowedHttpException) {
        $status = Response::HTTP_METHOD_NOT_ALLOWED;
        $e      = new MethodNotAllowedHttpException([], 'HTTP_METHOD_NOT_ALLOWED', $e);
    } elseif ($e instanceof NotFoundHttpException) {
        $status = Response::HTTP_NOT_FOUND;
        $e      = new NotFoundHttpException('HTTP_NOT_FOUND', $e);
    } elseif ($e instanceof AuthorizationException) {
        $status = Response::HTTP_FORBIDDEN;
        $e      = new AuthorizationException('HTTP_FORBIDDEN', $status);
    } elseif ($e instanceof \Dotenv\Exception\ValidationException && $e->getResponse()) {
        $status = Response::HTTP_BAD_REQUEST;
        $e      = new \Dotenv\Exception\ValidationException('HTTP_BAD_REQUEST', $status, $e);
    } elseif ($e) {
        $e = new HttpException($status, 'HTTP_INTERNAL_SERVER_ERROR');
    }

    return response()->json([
        'status'  => $status,
        'message' => $e->getMessage()
    ], $status);

 }
}

答案 5 :(得分:0)

我知道这是一个很老的问题,但是我偶然发现了它。 默认情况下,如果请求者“想要”,Lumen将返回JSON响应。

vendor/laravel/lumen-framework/src/Exceptions/Handler.php:110

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

这下降到 vendor/illuminate/http/Concerns/InteractsWithContentTypes.php:52

$acceptable = $this->getAcceptableContentTypes();
return isset($acceptable[0]) && Str::contains($acceptable[0], ['/json', '+json']);

这意味着,如果为“ application / json”指定“ Accept”标头,则流明将自动返回JSON响应。 例如curl -H "Accept: application/json" https://example.com/my-erroring-endpint

使用此功能,您不必编写自定义错误处理程序。