【问题标题】:Prefix text to ASP.NET Core response body为 ASP.NET Core 响应正文添加前缀文本
【发布时间】:2021-07-05 14:34:16
【问题描述】:

我正在尝试将字符串 )]}',\n 添加到任何 JSON 响应正文中。我认为IAsyncResultFilter 将是我需要使用的,但我没有运气。如果我使用下面的代码,它会将文本追加到响应中,因为调用await next() 会写入响应管道。但是,如果我在此之前尝试查看上下文,我无法判断响应实际上是什么来知道它是否是 JSON。

public class JsonPrefixFilter : IAsyncResultFilter
{
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        var executed = await next();
        var response = executed.HttpContext.Response;
        if (response.ContentType == null || !response.ContentType.StartsWith("application/json"))
            return;

        var prefix = Encoding.UTF8.GetBytes(")]}',\\n");
        var bytes = new ReadOnlyMemory<byte>(prefix);
        await response.BodyWriter.WriteAsync(bytes);
    }
}

【问题讨论】:

    标签: asp.net-core-3.1 .net-5


    【解决方案1】:

    您可以在 Steam 上使用 Seek 来倒带它。问题是,您只能继续添加到默认HttpResponseStream,它不支持搜索。 因此,您可以使用 this SO answer 的技术并暂时将其替换为 MemoryStream

    private Stream ReplaceBody(HttpResponse response)
    {
        var originBody = response.Body;
        response.Body = new MemoryStream();
        return originBody;
    }
    private async Task ReturnBodyAsync(HttpResponse response, Stream originalBody)
    {
        response.Body.Seek(0, SeekOrigin.Begin);
        await response.Body.CopyToAsync(originalBody);
        response.Body = originalBody;
    }
    public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
    {
        var originalBody = ReplaceBody(context.HttpContext.Response); // replace the default stream with MemoryStream
    
        await next(); // we probably dont care about the return of this call. it's all in the context
        var response = context.HttpContext.Response;
        if (response.ContentType == null || !response.ContentType.StartsWith("application/json"))
            return;
    
        var prefix = Encoding.UTF8.GetBytes(")]}',\\n");
        var bytes = new ReadOnlyMemory<byte>(prefix);
        response.Body.Seek(0, SeekOrigin.Begin); // now you can seek. but you will notice that it overwrites the response so you might need to make extra space in the buffer
        await response.BodyWriter.WriteAsync(bytes);
    
        await ReturnBodyAsync(context.HttpContext.Response, originalBody); // revert the reference, copy data into default stream and return it
    }
    

    由于您需要恢复对原始流的引用,这使情况变得更加复杂,因此您必须小心。

    This SO answer 有更多上下文。

    【讨论】:

    • 谢谢!这实际上并没有按原样工作,但基于这个答案和你指出我的另一个 SO 答案,我能够让它工作。一旦 SO 让我奖励赏金,我会按照你的方式传递。
    【解决方案2】:

    感谢 timur 的帖子,我能够想出这个可行的解决方案。

    public class JsonPrefixFilter : IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            var response = context.HttpContext.Response;
    
            // ASP.NET Core will always send the contents of the original Body stream back to the client.
            var originalBody = response.Body;
    
            // We want to write into a memory stream instead of the actual response body for now.
            var ms = new MemoryStream();
            response.Body = ms;
    
            // After this call the body is written into the memory stream and the properties
            // of the response object are populated.
            await next();
    
            if (response.ContentType != null && response.ContentType.StartsWith("application/json")) {
                var prefix = Encoding.UTF8.GetBytes(")]}',\\n");
    
                var prefixMemoryStream = new MemoryStream();
                await prefixMemoryStream.WriteAsync(prefix);
                await prefixMemoryStream.WriteAsync(ms.ToArray());
                prefixMemoryStream.Seek(0, SeekOrigin.Begin);
    
                // Now put the stream back that .NET wants to use and copy the memory stream to it.
                response.Body = originalBody;
                await prefixMemoryStream.CopyToAsync(response.Body);
            } else {
                // If it's not JSON, don't muck with the stream, so just put things back.
                response.Body = originalBody;
                ms.Seek(0, SeekOrigin.Begin);
                await ms.CopyToAsync(response.Body);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-30
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 2013-11-18
      • 1970-01-01
      • 2018-11-10
      相关资源
      最近更新 更多