Я занимаюсь разработкой с использованием PSR-7 (с Zend Expressive). Я разобрался с методом
ServerRequestInterface::withAttribute()
и мне было интересно, почему у объекта Response его нет.
Я хотел бы передать метаданные через промежуточное ПО после обработки на «стороне ответа».
Есть ли как-то передать «атрибуты» в Response для постобработки? Как лучше всего следовать руководству по архитектуре для достижения этой цели?
PSR-7
Спецификация определяет атрибуты только для запросов к серверу. Они в основном используются для хранения метаданных, полученных из входящего запроса, чтобы их можно было использовать позже, когда вы достигнете уровня своего домена.
С другой стороны, ответ обычно создается на уровне домена и пересекает весь стек промежуточного программного обеспечения перед его фактической отправкой клиенту. Таким образом, метаданные, добавленные в ответ, не будут иметь места, где они могут быть фактически использованы.
Я предполагаю, что если вы хотите передать данные из внутреннего промежуточного программного обеспечения во внешнее, лучшим способом является использование заголовков ответов.
Рекомендуется использовать объект запроса для передачи данных между Middleware. Ответ — это то, что отправляется клиенту, и вы хотите сохранить это в чистоте. Запрос живет только на сервере, и вы можете добавить (конфиденциальные данные) атрибуты для передачи. Если что-то пойдет не так или вы вернете ответ раньше, чем удаляете пользовательские данные, это не имеет значения, поскольку ваш ответ «чистый».
Также, если вам нужно передать данные: промежуточное программное обеспечение всегда выполняется в порядке, который он получает из конфигурации. Таким образом, вы можете убедиться, что объект запроса в MiddlewareX содержит данные, установленные MiddlewareY.
ОБНОВИТЬ: Пример передачи данных с помощью запроса.
Middleware 2 устанавливает объект мессенджера, который Middleware 4 может использовать для установки данных, необходимых для повторного выхода.
<?php
namespace Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class Middleware2
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$messenger = new Messenger();
// Do something else before next middleware
if ($next) {
$response = $next($request->withAttribute(Messenger::class, $messenger), $response);
}
// Do something with the Response after it got back
// At this point the $messenger object contains the updated data from Middleware4
return $response->withHeader('Content-Language', $locale);
}
}
Middleware 4 захватывает объект мессенджера и обновляет его значения.
<?php
namespace Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class Middleware4
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
{
$messenger = $request->getAttribute(Messenger::class);
$messenger->info('going in');
// Do something else before next middleware
if ($next) {
$response = $next($request->withAttribute(FlashMessenger::class, $messenger), $response);
}
// Do something with the Response after it got back
$messenger->info('going out');
return $response->withHeader('Content-Language', $locale);
}
}
Не уверен, что это «лучшая практика», но другая возможность — просто внедрить ваш объект данных в промежуточное ПО.
Промежуточное программное обеспечение 2 содержит объект-мессенджер и устанавливает для него некоторые данные:
<?php
namespace Middleware;
use Interop\Http\Server\MiddlewareInterface;
use Interop\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class Middleware2
{
private $messenger;
public function __construct(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$this->messenger->foo = 'bar';
$response = $handler->handle($request);
if ($this->messenger->foo = 'baz') {
return $response->withHeader('Really-Important-Header', 'Baz');
}
return $response;
}
}
Middleware 4 изменяет данные:
<?php
namespace Middleware;
use Interop\Http\Server\MiddlewareInterface;
use Interop\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class Middleware4
{
private $messenger;
public function __construct(Messenger $messenger)
{
$this->messenger = $messenger;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$this->messenger->foo = 'baz';
return $handler->handle($request);
}
}
Вы можете даже использовать одно из промежуточных программ в качестве мессенджера.
Предостережение: вы должны убедиться, что оба класса созданы с использованием одного и того же объекта мессенджера. Но это похоже на случай с большинством контейнеров для инъекций зависимости.