使用 Varnish 时修改路由和 url

Modify routes and url when using Varnish

我有一个项目,在 Slim 4 项目前面使用了 Varnish。由于一些项目的特殊性,原来的url应该被隐藏,传入的请求被改写成一些其他的header。

示例

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 package) 创建路由时,url 应该像这样生成:

想法:

  1. 修改原来的UriInterfaceobject不知道怎么改
  2. 为Twig-View写一个TwigExtension,修改url_for等的方法

第一个想法感觉更可靠,更适合做事。另一个意味着我需要覆盖辅助方法以基于 X-Orig-Host.

构建 url

知道如何修改 Uri / 可能会覆盖 create 方法吗?

提前致谢!

P. S.:我在 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}

您可以像这样实现自己的 ServerRequestCreatorInterface class:

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

要在 Twig 模板中输出完整的 url,请使用 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(...)