1

我有一个项目,在 Slim 4 项目之前使用了 Varnish。由于某些项目的特殊性,应隐藏原始 url,并将传入请求重写为其他一些标头。

例子

  • 对 demo.xyz 的原始调用即将来到 Varnish
  • Varnish 将请求转换为http://slimapp.dev/url/demo.xyz
  • 原始主机保存在标头中X-Orig-Host: demo.xyz

Slim App 需要检测它是否是 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. 为 Twig-View 写一个 TwigExtension 来修改方法url_for等等。

第一个想法感觉更可靠,也是正确的地方。另一个意味着我需要覆盖辅助方法来构建基于X-Orig-Host.

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

提前致谢!

PS:我在Slim Discourse中提出的问题相同。

更新 1

路由.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');
    });

};

中间件.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}
4

1 回答 1

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

要在 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(...)
于 2019-12-21T12:35:39.027 回答