web-dev-qa-db-ja.com

ミドルウェアの応答を変更する

私の要件:後続の別のミドルウェア(Mvcなど)からの応答からすべての「悪い言葉」をフィルタリングするミドルウェアを作成します。

問題:応答のストリーミング。したがって、すでに応答に書き込んでいる後続のミドルウェアからFilterBadWordsMiddlewareに戻ると、パーティーには遅すぎます...応答がすでに送信を開始しているため、既知のエラーresponse has already started...

これは多くのさまざまな状況での要件なので、どのように対処すればよいでしょうか?

14
Matthias

送信を防ぐために、応答ストリームをMemoryStreamに置き換えます。応答が変更された後、元のストリームを返します。

public class EditResponseMiddleware
{
    private readonly RequestDelegate _next;

    public EditResponseMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var originBody = context.Response.Body;

        var newBody = new MemoryStream();

        context.Response.Body = newBody;

        await _next(context);

        newBody.Seek(0, SeekOrigin.Begin);

        string json = new StreamReader(newBody).ReadToEnd();

        context.Response.Body = originBody;

        await context.Response.WriteAsync(modifiedJson);
    }
}

これは回避策であり、パフォーマンスの問題を引き起こす可能性があります。私はここでより良い解決策を見たいと思っています。

9
Ilya Chumakov

私が使用したコードに基づく簡単なバージョン:

/// <summary>
    /// The middleware Invoke method.
    /// </summary>
    /// <param name="httpContext">The current <see cref="HttpContext"/>.</param>
    /// <returns>A Task to support async calls.</returns>
    public async Task Invoke(HttpContext httpContext)
    {
        var originBody = httpContext.Response.Body;
        try
        {
            var memStream = new MemoryStream();
            httpContext.Response.Body = memStream;

            await _next(httpContext).ConfigureAwait(false);

            memStream.Position = 0;
            var responseBody = new StreamReader(memStream).ReadToEnd();

            //Custom logic to modify response
            responseBody = responseBody.Replace("hello", "hi", StringComparison.InvariantCultureIgnoreCase);

            var memoryStreamModified = new MemoryStream();
            var sw = new StreamWriter(memoryStreamModified);
            sw.Write(responseBody);
            sw.Flush();
            memoryStreamModified.Position = 0;

            await memoryStreamModified.CopyToAsync(originBody).ConfigureAwait(false);
        }
        finally
        {
            httpContext.Response.Body = originBody;
        }
    }
0
Ayushmati