web-dev-qa-db-fra.com

Modifier la réponse du middleware

Mon exigence: écrire un middleware qui filtre tous les "mauvais mots" d'une réponse provenant d'un autre middleware ultérieur (par exemple Mvc).

Le problème: le streaming de la réponse. Donc, quand nous revenons à notre FilterBadWordsMiddleware à partir d'un middleware suivant, qui a déjà écrit dans la réponse, nous sommes trop en retard pour le parti ... car la réponse a déjà commencé à envoyer, ce qui donne l'erreur bien connue response has already started...

Donc, puisque c'est une exigence dans de nombreuses situations différentes - comment y faire face?

14
Matthias

Remplacez un flux de réponse par MemoryStream pour empêcher son envoi. Renvoyez le flux d'origine une fois la réponse modifiée:

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

C'est une solution de contournement et cela peut causer des problèmes de performances. J'espère voir une meilleure solution ici.

9
Ilya Chumakov

Une version plus simple basée sur le code que j'ai utilisé:

/// <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