问题
I have a project where Varnish is used in front of a Slim 4 project. Due to some project specialities, the original url should be hidden and the incoming request is rewritten to some other headers.
Example
- Original call to demo.xyz is coming to Varnish
- Varnish is transforming the request to
http://slimapp.dev/url/demo.xyz
- The original host is saved in the header with
X-Orig-Host: demo.xyz
The Slim App needs to detect if it is a Varnish request (I already got that) and needs to transform the routes.
Routes
Without Varnish:
$app->group('/url/{url}', function (RouteCollectorProxy $group) {
$group->get('[/city/{city}]', IndexAction::class)->setName('home');
$group->get('/search[/{query}]', SearchQueryAction::class)->setName('search-query');
});
With Varnish:
$app->get('[/city/{city}]', IndexAction::class)->setName('home');
$app->get('/search[/{query}]', SearchQueryAction::class)->setName('search-query');
So when creating a route with url_for
(Twig-View package) the urls should be generated like that:
- Route w/o Varnish:
http://slimapp.dev/url/demo.xyz/article/123
- Route w/ Varnish:
http://demo.xyz/article/123
Ideas:
- Modify the original UriInterface object but I have no idea how.
- Write a TwigExtension for Twig-View to modify the methods for
url_for
and so on.
The first ideas feels kind of more reliable and the right place to do. The other one would mean I would need to overwrite the helper methods to build the url based on the X-Orig-Host
.
Any idea how I can modify the Uri / probably overwriting the create
method?
Thanks in advance!
P. S.: The same questions I placed in Slim Discourse.
UPDATE 1
routes.php
return function (App $app) {
$app->get('/', function () {
die('No URL defined.');
})->setName('root');
$app->group('/url/{url}', function (RouteCollectorProxy $group) {
$group->get('[/city/{city}]', IndexAction::class)->setName('home');
# Internal page search
$group->get('/search[/{query}]', SearchQueryAction::class)->setName('search-query');
});
};
middleware.php
return function(App $app) {
$c = $app->getContainer();
$app->addBodyParsingMiddleware();
$app->add(TwigMiddleware::class);
$app->addRoutingMiddleware();
$app->add(VarnishBasePathMiddleware::class);
$displayErrorDetails = $c->get(Configuration::class)->getBool('displayErrorDetails');
$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, false, false);
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->registerErrorRenderer('text/html', HtmlErrorRenderer::class);
$errorHandler->registerErrorRenderer('application/json', JsonErrorRenderer::class);
};
Error message
[404] Not found. in /usr/share/nginx/html/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php on line 91.
Backtrace: #0 /usr/share/nginx/html/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php(57): Slim\Middleware\RoutingMiddleware->performRouting(Object(Slim\Psr7\Request)) #1 /usr/share/nginx/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(132): Slim\Middleware\RoutingMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #2 /usr/share/nginx/html/src/Middleware/VarnishBasePathMiddleware.php(28): class@anonymous->handle(Object(Slim\Psr7\Request)) #3 /usr/share/nginx/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(180): App\Middleware\VarnishBasePathMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #4 /usr/share/nginx/html/vendor/slim/twig-view/src/TwigMiddleware.php(125): class@anonymous->handle(Object(Slim\Psr7\Request)) #5 /usr/share/nginx/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(180): Slim\Views\TwigMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #6 /usr/share/nginx/html/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php(89): class@anonymous->handle(Object(Slim\Psr7\Request)) #7 /usr/share/nginx/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(132): Slim\Middleware\ErrorMiddleware->process(Object(Slim\Psr7\Request), Object(class@anonymous)) #8 /usr/share/nginx/html/vendor/slim/slim/Slim/MiddlewareDispatcher.php(73): class@anonymous->handle(Object(Slim\Psr7\Request)) #9 /usr/share/nginx/html/vendor/slim/slim/Slim/App.php(208): Slim\MiddlewareDispatcher->handle(Object(Slim\Psr7\Request)) #10 /usr/share/nginx/html/public/index.php(57): Slim\App->handle(Object(Slim\Psr7\Request)) #11 {main}
回答1:
You can implement you own ServerRequestCreatorInterface
class like this:
use Psr\Http\Message\ServerRequestInterface;
use Slim\Factory\ServerRequestCreatorFactory;
use Slim\Interfaces\ServerRequestCreatorInterface;
use Slim\Psr7\Factory\ServerRequestFactory;
class VarnishServerRequestCreator implements ServerRequestCreatorInterface
{
public function createServerRequestFromGlobals(): ServerRequestInterface
{
$request = ServerRequestFactory::createFromGlobals();
$serverParams = $request->getServerParams();
if (isset($serverParams['X-Orig-Host'])) {
// Replace the hostname
$uri = $request->getUri()->withHost($serverParams['X-Orig-Host']);
$request = $request->withUri($uri);
}
return $request;
}
}
ServerRequestCreatorFactory::setServerRequestCreator(new VarnishServerRequestCreator());
To output the full url in your Twig templates use the full_url_for
function. Example:
{{ full_url_for('article') }}
Output:
https://demo.xyz/article
To change the base path you could add this special middleware:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\App;
final class VarnishBasePathMiddleware implements MiddlewareInterface
{
/**
* @var App The slim app
*/
private $app;
public function __construct(App $app)
{
$this->app = $app;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$serverParams = $request->getServerParams();
// Detect Varnish
if (isset($serverParams['X-Orig-Host'])) {
// Change the base path
$this->app->setBasePath('/url/demo.xyz');
}
return $handler->handle($request);
}
}
The VarnishBasePathMiddleware
must be add after the RoutingMiddleware
$app->add(TwigMiddleware::class);
$app->addRoutingMiddleware();
$app->add(\App\Middleware\VarnishBasePathMiddleware::class); // <--- here
$app->addErrorMiddleware(...)
来源:https://stackoverflow.com/questions/59434991/modify-routes-and-url-when-using-varnish