webdevqa.jp.net

OWINミドルウェアからの応答オブジェクトの変更

私のOWINミドルウェアはこんな感じです。 (フレームワークはASP.NET Web APIです)。

public class MyMiddleware : OwinMiddleware
{
    public MyMiddleware(OwinMiddleware next) : base(next) { }

    public override async Task Invoke(OwinRequest request, OwinResponse response)
    {
        var header = request.GetHeader("X-Whatever-Header");

        await Next.Invoke(request, response);

        response.SetHeader("X-MyResponse-Header", "Some Value");
        response.StatusCode = 403;

    }
}

質問:

  1. OwinMiddlewareから派生することをお勧めしますか? Katanaソースでは、ミドルウェアクラスの一部がOwinMiddlewareから派生しているものとそうでないものがあることがわかります。

  2. リクエストヘッダーを確認できます。ミドルウェアでNext.Invokeの後に応答ヘッダーまたはステータスコードを設定しても、クライアントに返される応答には影響しません。しかし、Next.Invokeを呼び出す前に応答ヘッダーまたはステータスを設定すると、ヘッダーと設定したステータスを含む応答がクライアントに返されます。これらを設定する正しい方法は何ですか?

28
Badri
  1. はい、OwinMiddlewareから派生させることをお勧めします。一部のミドルウェアクラスがOwinMiddlewareから派生していないのは、クラスが最近導入されたため、まだ切り替えられていないためです。または、何らかの理由でアセンブリがMicrosoft.Owinアセンブリに依存するのを避けるため。

  2. Invoke on Nextを呼び出した後に応答に設定されていると思われる理由が機能しないのは、誰かが応答本文ストリームへの書き込みを開始するとすぐに応答HTTPヘッダーが送信されるためです。したがって、ミドルウェアコンポーネントが応答本文への書き込みを開始した後にステータスコードまたはHTTPヘッダーを変更しても、何の影響もありません。

OWINが提供するOnSendingHeadersコールバックを使用することで、試すことができます。使い方は次のとおりです。

public override async Task Invoke(IOwinContext context)
{
   var response = context.Response;
   var request =  context.Request;

   response.OnSendingHeaders(state =>
   {
       var resp = (OwinResponse)state;
       resp.Headers.Add("X-MyResponse-Header", "Some Value");
       resp.StatusCode = 403;
       resp.ReasonPhrase = "Forbidden";
    }, response);

  var header = request.Headers["X-Whatever-Header"];

  await Next.Invoke(context);
}

私の回答を更新してくれたbiscuit314へのクレジット。

29

Youssefの優れた答えを編集してマイナーなバグを修正し、OwinMiddlewareがどのように機能するかで例を更新してみました。

編集は拒否されました(まあ、1人が承認、1人が少なすぎるため拒否、2人が少なすぎるため拒否)。

Youssefのコードのそのバージョンは次のとおりです。

public override async Task Invoke(IOwinContext context)
{
  var response = context.Response;
  var request =  context.Request;

  response.OnSendingHeaders(state =>
    {
        var resp = (OwinResponse)state;
        resp.Headers.Add("X-MyResponse-Header", "Some Value");
        resp.StatusCode = 403;
        resp.ReasonPhrase = "Forbidden"; // if you're going to change the status code
                                         // you probably should also change the reason phrase
    }, response);

  var header = request.Headers["X-Whatever-Header"];

  await Next.Invoke(context);
}
9
biscuit314

このコードを使用して、すべてのリクエストにかかる時間を取得しました。

appBuilder.Use(async (context, next) =>
        {
            var watch = new Stopwatch();
            watch.Start();
            await next();
            watch.Stop();
            context.Response.Headers.Set("ResponseTime", watch.Elapsed.Seconds.ToString());
        });
0