Modify middleware response

前端 未结 4 1923
粉色の甜心
粉色の甜心 2020-12-06 00:30

My requirement: write a middleware that filters all \"bad words\" out of a response that comes from another subsequent middleware (e.g. Mvc).

The problem: streaming

4条回答
  •  南笙
    南笙 (楼主)
    2020-12-06 01:27

    Unfortunately I'm not allowed to comment since my score is too low. So just wanted to post my extension of the excellent top solution, and a modification for .NET Core 3.0+

    First of all

    context.Request.EnableRewind();
    

    has been changed to

    context.Request.EnableBuffering();
    

    in .NET Core 3.0+

    And here's how I read/write the body content:

    First a filter, so we just modify the content types we're interested in

    private static readonly IEnumerable validContentTypes = new HashSet() { "text/html", "application/json", "application/javascript" };
    

    It's a solution for transforming nuggeted texts like [[[Translate me]]] into its translation. This way I can just mark up everything that needs to be translated, read the po-file we've gotten from the translator, and then do the translation replacement in the output stream - regardless if the nuggeted texts is in a razor view, javascript or ... whatever. Kind of like the TurquoiseOwl i18n package does, but in .NET Core, which that excellent package unfortunately doesn't support.

    ...
    
    if (modifyResponse)
    {
        //as we replaced the Response.Body with a MemoryStream instance before,
        //here we can read/write Response.Body
        //containing the data written by middlewares down the pipeline
    
        var contentType = context.Response.ContentType?.ToLower();
        contentType = contentType?.Split(';', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();   // Filter out text/html from "text/html; charset=utf-8"
    
        if (validContentTypes.Contains(contentType))
        {
            using (var streamReader = new StreamReader(context.Response.Body))
            {
                // Read the body
                context.Response.Body.Seek(0, SeekOrigin.Begin);
                var responseBody = await streamReader.ReadToEndAsync();
    
                // Replace [[[Bananas]]] with translated texts - or Bananas if a translation is missing
                responseBody = NuggetReplacer.ReplaceNuggets(poCatalog, responseBody);
    
                // Create a new stream with the modified body, and reset the content length to match the new stream
                var requestContent = new StringContent(responseBody, Encoding.UTF8, contentType);
                context.Response.Body = await requestContent.ReadAsStreamAsync();//modified stream
                context.Response.ContentLength = context.Response.Body.Length;
            }
        }
    
        //finally, write modified data to originBody and set it back as Response.Body value
        ReturnBody(context.Response, originBody);
    }
    ...
    
    private void ReturnBody(HttpResponse response, Stream originBody)
    {
        response.Body.Seek(0, SeekOrigin.Begin);
        response.Body.CopyToAsync(originBody);
        response.Body = originBody;
    }
    

提交回复
热议问题