Измените маршруты и URL-адрес при использовании Varnish

У меня есть проект, в котором Varnish используется перед проектом Slim 4. Из-за некоторых особенностей проекта исходный URL-адрес должен быть скрыт, а входящий запрос переписан на некоторые другие заголовки.

пример

  • Оригинальный вызов demo.xyz прибывает в Varnish
  • Varnish преобразует запрос в http://slimapp.dev/url/demo.xyz
  • Исходный хост сохраняется в заголовке с X-Orig-Host: demo.xyz

Приложение Slim должно определить, является ли это запросом 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');
});

С лаком:

$app->get('[/city/{city}]', IndexAction::class)->setName('home');
$app->get('/search[/{query}]', SearchQueryAction::class)->setName('search-query');

Поэтому при создании маршрута с url_for( Пакет Twig-View) URL-адреса должны быть сгенерированы следующим образом:

  • Маршрут без лака: http://slimapp.dev/url/demo.xyz/article/123
  • Маршрут с лаком: http://demo.xyz/article/123

Идеи:

  1. Измените исходный объект UriInterface, но я понятия не имею, как это сделать.
  2. Напишите TwigExtension для Twig-View, чтобы изменить методы для url_for и так далее.

Первые идеи кажутся более надежными и правильными. Другой будет означать, что мне нужно будет перезаписать вспомогательные методы для создания URL-адреса на основеX-Orig-Host.

Любая идея, как я могу изменить Uri /, вероятно, перезаписать create метод?

Заранее спасибо!

PS: Те же вопросы, что я задавал в Slim Discourse.

ОБНОВЛЕНИЕ 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);
};

Сообщение об ошибке

[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 ответ

Решение

Вы можете реализовать свои собственные ServerRequestCreatorInterface класс вроде этого:

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());

Чтобы вывести полный URL-адрес в ваших шаблонах Twig, используйте full_url_forфункция. Пример:

{{ full_url_for('article') }}

Выход:

https://demo.xyz/article

Чтобы изменить базовый путь, вы можете добавить это специальное промежуточное ПО:

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

В VarnishBasePathMiddleware необходимо добавить после RoutingMiddleware

$app->add(TwigMiddleware::class);

$app->addRoutingMiddleware();

$app->add(\App\Middleware\VarnishBasePathMiddleware::class); // <--- here

$app->addErrorMiddleware(...)
Другие вопросы по тегам