使用 Varnish 时修改路由和 url
Modify routes and url when using Varnish
我有一个项目,在 Slim 4 项目前面使用了 Varnish。由于一些项目的特殊性,原来的url应该被隐藏,传入的请求被改写成一些其他的header。
示例
- 对 demo.xyz 的原始调用将转至 Varnish
- Varnish 正在将请求转换为
http://slimapp.dev/url/demo.xyz
- 原主机保存在header和
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 package) 创建路由时,url 应该像这样生成:
- 路线w/o清漆:
http://slimapp.dev/url/demo.xyz/article/123
- 带清漆的路线:
http://demo.xyz/article/123
想法:
- 修改原来的UriInterfaceobject不知道怎么改
- 为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(...)
我有一个项目,在 Slim 4 项目前面使用了 Varnish。由于一些项目的特殊性,原来的url应该被隐藏,传入的请求被改写成一些其他的header。
示例
- 对 demo.xyz 的原始调用将转至 Varnish
- Varnish 正在将请求转换为
http://slimapp.dev/url/demo.xyz
- 原主机保存在header和
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 package) 创建路由时,url 应该像这样生成:
- 路线w/o清漆:
http://slimapp.dev/url/demo.xyz/article/123
- 带清漆的路线:
http://demo.xyz/article/123
想法:
- 修改原来的UriInterfaceobject不知道怎么改
- 为Twig-View写一个TwigExtension,修改
url_for
等的方法
第一个想法感觉更可靠,更适合做事。另一个意味着我需要覆盖辅助方法以基于 X-Orig-Host
.
知道如何修改 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(...)