-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get middlewares stack in ErrorHandler #2999
Comments
I don't think that the middleware stack should be accessed by anything else but the The solution to your problem is to create a custom This emitter can be modularly used in multiple places within your application. I'm aware that the typical way to handle CORS is through middleware but that doesn't make it the only way. You can see the usage in the index.php from Slim-Skeleton. Hope that helps. |
Hmmm, what about an option in next major release to apply middleware even when exception catched? Something like: $app->add($middleware, $applyOnExceptionCatch); |
@ybelenko it's not the right way to achieve what you're trying to achieve. Again, a custom |
I've checked |
CORS is a pain -- I've put my CORS code directly in index.php before Slim is invoked. See: https://github.com/RyanNerd/rxchart-app/blob/master/public/index.php $requestMethod = $_SERVER['REQUEST_METHOD'];
// Is this a pre-flight request (the request method is OPTIONS)? Then start output buffering.
if ($requestMethod === 'OPTIONS') {
ob_start();
}
// Allow for all origins and credentials. Also allow GET, POST, PATCH, DELETE and OPTIONS request verbs
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
header('Access-Control-Allow-Methods: GET, POST, PATCH, OPTIONS, DELETE');
// If this is a pre-flight request (the request method is OPTIONS)? Then flush the output buffer and exit.
if ($requestMethod === 'OPTIONS') {
ob_end_flush();
exit();
}
// Code that starts the Slim app. HTH |
@RyanNerd thanks, it's obvious solution. I was looking for more elegant way... And I don't want to reinvent the wheel when I can use stable CORS package, unfortunately the most popular one implemented as middleware - tuupola/cors-middleware. |
It's just a wrapper for neomerx/cors-psr7 |
That's my custom emitter(not really elegant) which solves CORS with neomerx/cors-psr7 v2.0.2: <?php declare(strict_types=1);
namespace App;
use Neomerx\Cors\Contracts\AnalysisResultInterface;
use Neomerx\Cors\Contracts\AnalyzerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\HttpBadRequestException;
use Slim\Middleware\ErrorMiddleware;
use Slim\ResponseEmitter as SlimResponseEmitter;
/**
* @link https://github.com/slimphp/Slim-Skeleton/blob/master/src/Application/ResponseEmitter/ResponseEmitter.php
*/
class ResponseEmitter extends SlimResponseEmitter
{
/**
* @var ServerRequestInterface
*/
protected $request;
/**
* @var ErrorMiddleware
*/
protected $errorMiddleware;
/**
* @var AnalyzerInterface
*/
protected $analyzer;
/**
* Custom emitter
*
* @param ServerRequestInterface $request Request
* @param ErrorMiddleware $errorMiddleware Error middleware
* @param AnalyzerInterface $analyzer Cors analyzer
* @param int $responseChunkSize
*/
public function __construct(
ServerRequestInterface $request,
ErrorMiddleware $errorMiddleware,
AnalyzerInterface $analyzer,
int $responseChunkSize = 4096
) {
parent::__construct($responseChunkSize);
$this->request = $request;
$this->errorMiddleware = $errorMiddleware;
$this->analyzer = $analyzer;
}
/**
* {@inheritDoc}
*/
public function emit(ResponseInterface $response): void
{
// slightly modified CORS handler from package documentation example
// @link https://github.com/neomerx/cors-psr7#sample-usage
$cors = $this->analyzer->analyze($this->request);
$exception = null;
switch ($cors->getRequestType()) {
case AnalysisResultInterface::ERR_NO_HOST_HEADER:
$exception = new HttpBadRequestException($this->request, 'CORS: No Host header in request');
break;
case AnalysisResultInterface::ERR_ORIGIN_NOT_ALLOWED:
$exception = new HttpBadRequestException($this->request, 'CORS: Request origin is not allowed');
break;
case AnalysisResultInterface::ERR_METHOD_NOT_SUPPORTED:
$exception = new HttpBadRequestException($this->request, 'CORS: Request method is not supported');
break;
case AnalysisResultInterface::ERR_HEADERS_NOT_SUPPORTED:
$exception = new HttpBadRequestException($this->request, 'CORS: Request headers are not supported');
break;
case AnalysisResultInterface::TYPE_REQUEST_OUT_OF_CORS_SCOPE:
// do nothing
break;
case AnalysisResultInterface::TYPE_PRE_FLIGHT_REQUEST:
default:
// actual CORS request
$corsHeaders = $cors->getResponseHeaders();
// add CORS headers to Response $response
foreach ($corsHeaders as $name => $value) {
$response = $response->withHeader($name, $value);
}
}
if ($exception instanceof \Throwable) {
$response = $this->errorMiddleware->handleException($this->request, $exception);
}
parent::emit($response);
}
} I don't like that I have to pass |
Sorry to bothering you guys again. I'm a bit confused right now. Just noticed this Cook Book - Setting up CORS. It looks fresh to me. Can we say that handling CORS via middleware is recommended way right now? Will your doc example add CORS headers when exception thrown? |
@ybelenko the best way to do it is via using a custom https://github.com/slimphp/Slim-Skeleton/blob/master/public/index.php#L79-L82 |
While Slim4 doc applies CORS headers via middleware but their code team member recommends to use custom response emitter. Ref: slimphp/Slim#2999 (comment)
* Add lazy CORS implementation While Slim4 doc applies CORS headers via middleware but their code team member recommends to use custom response emitter. Ref: slimphp/Slim#2999 (comment) * Refresh samples
Is there any elegant way to retrieve middleware stack or at least container in
ErrorHandler
?It's related to CORS middleware, it needs to be applied after exception catch. I want to override
respond()
method ofErrorHandler
retrieve middlewares array, find CORS middleware and apply it to$request
.Of course I can add
$container
argument to extendedErrorHandler
class, then I can retrieve CORS settings, instantiate new CORS middleware handler and execute it, but it seems like not a proper way to achieve this.I think that
ErrorHandler
should have access to middlewares as it important part of the application and business logic.The text was updated successfully, but these errors were encountered: