Modify routes and url when using Varnish

早过忘川 提交于 2020-02-05 04:06:26

问题


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:

  1. Modify the original UriInterface object but I have no idea how.
  2. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!