2016-07-08 4 views
1

私はPSR-7(Zend Expressive)を使って開発しています。私はその方法を考え出しましたレスポンスオブジェクトのPSR-7 "attributes"

ServerRequestInterface::withAttribute() 

私はなぜオブジェクトレスポンスが持っていないのか不思議でした。 "レスポンス側"の処理後にミドルウェアを介してメタデータを渡したいと思います。 レスポンスに後処理のための「属性」を渡すことはありますか?それを達成するために、アーキテクチャーのガイドラインに従うのに最適な方法は何ですか?

答えて

2

PSR-7仕様では、サーバー要求に対してのみ属性が定義されています。主に着信要求から推測されたメタデータを格納するために使用されるため、後でドメイン層に到達すると使用できます。

一方、レスポンスは通常、ドメイン層で作成され、実際にクライアントに送信される前にすべてのミドルウェアスタックをトラバースします。したがって、レスポンスに追加されるメタデータには、実際に使用できる場所がありません。

内部ミドルウェアから外部ミドルウェアにデータを渡す場合は、レスポンスヘッダーを使用するのが最善の方法です。

+1

これは私がやっていることですが、「属性」のようなものがあれば良いと思いますので、送信前にこれらのカスタムヘッダーを応答から削除する必要はありません。 – tornellas

2

ベスト・プラクティスでは、リクエスト・オブジェクトを使用してミドルウェア間でデータを受け渡しています。応答はクライアントに送信されるもので、これをきれいに保つ必要があります。リクエストはサーバー上にのみ存在し、(機密データ)属性を追加して渡すことができます。何かがうまくいかない場合や、カスタムデータを削除する前に早めに返信した場合は、あなたの応答が「きれい」なので問題はありません。

また、データを渡す必要がある場合:ミドルウェアは常に設定から取得した順番で実行されます。これにより、MiddlewareXの要求オブジェクトにMiddlewareYが設定したデータが含まれていることを確認できます。

更新: aリクエストでデータを渡す方法の例。

ミドルウェア2は、ミドルウェア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); 
    } 
} 

ミドルウェア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); 
    } 
} 
+0

ミドルウェア1 - >ミドルウェア2 - >ミドルウェア3 - >ミドルウェア4 ミドルウェア4にはいくつかのメタデータが渡され、ミドルウェア2がそれを使用するとします。私は "属性"なしでこれを行う方法を見ることができません。これは、 "最高で清潔な"方法です、IMHO。 「X-Header」を使用することは可能ですが、逆の流れに沿って除去するなどの欠点があります。分かりますか? – tornellas

+1

ミドルウェア4からミドルウェア2にデータを渡すには、ロード順序を変更し、ミドルウェア4がミドルウェア2の前にロードされていることを確認する必要があります。または、ミドルウェア2でリクエスト内でオブジェクトを利用できるようにすることもできます。ミドルウェア4は、そのオブジェクトを要求から取得し、必要なデータを設定します。その後、応答が途中で戻ってくると、データはミドルウェア2で設定/更新され、それに応じて応答を変更することができます。応答が出ているときにデータを更新することすらできます。 – xtreamwayz

+0

@tornellasオブジェクトを使用してデータを渡す方法の例を追加しました。 – xtreamwayz

0

これが「ベストプラクティス」であるかどうかはわかりませんが、データオブジェクトをミドルウェアに注入するだけです。

ミドルウェア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; 
     } 
} 

ミドルウェア4は、データを変更します。あなたも、メッセンジャーなどのミドルウェアの1使用する可能性があります

<?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); 
     } 
} 

注意:両方のクラスが同じメッセンジャーオブジェクトで構築されていることを確認する必要があります。しかし、それはほとんどの依存性注入容器の場合のようです。

関連する問題