Slim Framework 매뉴얼 미들웨어 – 라우팅, 에러

라우팅 미들웨어 (Routing Middleware)

라우팅은 미들웨어로 구현되었습니다. 기본 라우터로 FastRoute를 사용하고 있지만 이 라우터에 단단히 결합되어 있지는 않습니다. 다른 라우팅 라이브러리를 구현하려면 라우팅 인터페이스 구현을 직접 생성하면 됩니다. DispatcherInterface, RouteCollectorInterface, RouteParserInterface, RouteResolverInterface Slim의 구성 요소와 라우팅 라이브러리 사이에 브리지를 만듭니다. determineRouteBeforeAppMiddleware를 사용하는 경우 호출 실행 직전 프로그램에 Middleware\RoutingMiddleware미들웨어를 추가하여 이전 동작을 유지해야 합니다.

사용법

<?php

use Slim\Factory\AppFactory;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
// Add Routing Middleware
$app->addRoutingMiddleware();
​
// ...
​
$app->run();

에러 미들웨어 (Error Middleware)

오류를 예측할 수는 없지만 예상할 수는 있습니다. 각 Slim Framework 응용 프로그램에는 검색되지 않은 모든 PHP 예외를 수신하는 오류 처리기가 있습니다. 이 오류 처리기는 현재 HTTP 요청 및 응답 개체도 수신합니다. 오류 처리기는 HTTP 클라이언트에 반환될 적절한 응답 오브젝트를 준비하고 반환해야 합니다.

사용법

<?php

use Slim\Factory\AppFactory;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
/**
 * The routing middleware should be added earlier than the ErrorMiddleware
 * Otherwise exceptions thrown from it will not be handled by the middleware
 */
$app->addRoutingMiddleware();
​
/**
 * Add Error Middleware
 *
 * @param bool                  $displayErrorDetails -> Should be set to false in production
 * @param bool                  $logErrors -> Parameter is passed to the default ErrorHandler
 * @param bool                  $logErrorDetails -> Display error details in error log
 * @param LoggerInterface|null  $logger -> Optional PSR-3 Logger  
 *
 * Note: This middleware should be added last. It will not handle any exceptions/errors
 * for middleware added after it.
 */
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
​
// ...
​
$app->run();

사용자 지정 오류 처리기 추가 (Adding Custom Error Handlers)

이제 예외 또는 버릴 수 있는 유형에 대해 사용자 지정 핸들러를 매핑할 수 있습니다.

<?php

use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Slim\Factory\AppFactory;
use Slim\Psr7\Response;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
// Add Routing Middleware
$app->addRoutingMiddleware();
​
// Define Custom Error Handler
$customErrorHandler = function (
    ServerRequestInterface $request,
    Throwable $exception,
    bool $displayErrorDetails,
    bool $logErrors,
    bool $logErrorDetails,
    ?LoggerInterface $logger = null
) use ($app) {
    $logger->error($exception->getMessage());
​
    $payload = ['error' => $exception->getMessage()];
​
    $response = $app->getResponseFactory()->createResponse();
    $response->getBody()->write(
        json_encode($payload, JSON_UNESCAPED_UNICODE)
    );
​
    return $response;
};
​
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($customErrorHandler);
​
// ...
​
$app->run();

에러 로깅 (Error Logging)

Slim과 함께 제공되는 기본값인 ErrorHandler에 사용자 지정 오류 로깅을 파이프로 연결하려는 경우 두 가지 방법이 있습니다.

첫 번째 방법을 사용하면 ErrorHandler를 확장하고 logError() 메서드를 스텁할 수 있습니다.

<?php

namespace MyApp\Handlers;
​
use Slim\Handlers\ErrorHandler;
​
class MyErrorHandler extends ErrorHandler
{
    protected function logError(string $error): void
    {
        // Insert custom error logging function.
    }
}
​
<?php

use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
// Add Routing Middleware
$app->addRoutingMiddleware();
​
// Instantiate Your Custom Error Handler
$myErrorHandler = new MyErrorHandler($app->getCallableResolver(), $app->getResponseFactory());
​
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($myErrorHandler);
​
// ...
​
$app->run();

두 번째 방법을 사용하면 인기 있는 Monolog 라이브러리와 같이 PSR-3 표준,을 준수하는 로거를 제공할 수 있습니다.

<?php

use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
// Add Routing Middleware
$app->addRoutingMiddleware();
​
// Monolog Example
$logger = new Logger('app');
$streamHandler = new StreamHandler(__DIR__ . '/var/log', 100);
$logger->pushHandler($streamHandler);
​
// Add Error Middleware with Logger
$errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger);
​
// ...
​
$app->run();

오류 처리/렌더링 (Error Handling/Rendering)

렌더링이 드디어 핸들링에서 분리되었습니다. ErrorRenderers의 도움을 받아 여전히 콘텐츠 유형을 탐지하고 적절히 렌더링합니다. 핵심 ErrorHandler는 완전히 리팩터링된 ‘AbstractErrorHandler’ 클래스를 확장합니다. 기본적으로 지원되는 콘텐츠 유형에 적합한 ‘ErrorRenderer’를 호출합니다. 핵심 ‘ErrorHandler’는 다음과 같은 콘텐츠 유형에 대한 렌더러를 정의합니다.

  • application/json
  • application/xml and text/xml
  • text/html
  • text/plain

모든 콘텐츠 유형에 대해 자신의 오류 렌더러를 등록할 수 있습니다. 그러므로 먼저 \Slim\Interfaces\ErrorRendererInterface를 구현하는 새로운 오류 렌더러를 정의합니다.

<?php

use Slim\Interfaces\ErrorRendererInterface;
use Throwable;
​
class MyCustomErrorRenderer implements ErrorRendererInterface
{
    public function __invoke(Throwable $exception, bool $displayErrorDetails): string
    {
        return 'My awesome format';
    }
}

그리고 코어 에러 핸들러에 에러 렌더러를 등록합니다. 아래의 예에서 우리는 ‘text/html’ 콘텐츠 타입에 사용할 렌더러를 등록할 것입니다.

<?php

use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
​
require __DIR__ . '/../vendor/autoload.php';
​
$app = AppFactory::create();
​
// Add Routing Middleware
$app->addRoutingMiddleware();
​
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
​
// Get the default error handler and register my custom error renderer.
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->registerErrorRenderer('text/html', MyCustomErrorRenderer::class);
​
// ...
​
$app->run();

오류 렌더링에 대해 특정 콘텐츠 유형 강제 적용 (Force a specific content type for error rendering)

기본적으로 오류 처리기는 요청의 Accept 헤더를 사용하여 오류 렌더러를 탐지하려고 합니다. 오류 핸들러가 특정 오류 렌더러를 사용하도록 강제해야 할 경우 다음을 작성할 수 있습니다.

$errorHandler->forceContentType('application/json');

새 HTTP 예외 (New HTTP Exceptions)

The base class HttpSpecializedException extends Exception and comes with the following sub classes:

애플리케이션 내에 명명된 HTTP 예외를 추가했습니다. 이러한 예외는 네이티브 렌더러에서 잘 작동합니다. 이들은 각각 ‘description’과 ‘title’ 속성을 가질 수 있으며 네이티브 HTML 렌더러가 호출될 때 조금 더 많은 통찰력을 제공할 수 있다.

기본 클래스 HttpSpecializedExceptionException을 확장하며 다음과 같은 하위 클래스가 제공됩니다.

  • HttpBadRequestException
  • HttpForbiddenException
  • HttpInternalServerErrorException
  • HttpMethodNotAllowedException
  • HttpNotFoundException
  • HttpNotImplementedException
  • HttpUnauthorizedException

기본 리포지토리에서 제공하지 않기로 결정한 다른 응답 코드가 필요한 경우 ‘HttpSpecializedException’ 클래스를 확장할 수 있습니다. 예를 들어 기본 게이트웨이와 동일하게 동작하는 504 게이트웨이 시간 초과 예외를 원할 경우 다음을 수행합니다.

class HttpForbiddenException extends HttpSpecializedException
{
    protected $code = 504;
    protected $message = 'Gateway Timeout.';
    protected $title = '504 Gateway Timeout';
    protected $description = 'Timed out before receiving response from the upstream server.';
}