【问题标题】:How to read the HttpResponse Body?如何阅读 HttpResponse 正文?
【发布时间】:2021-02-02 00:54:52
【问题描述】:

我有一个带有请求和响应日志中间件的 .NET Core Web API 项目。我在Startup 文件中的Configure 方法中注册了两个中间件文件

app.UseMiddleware<RequestLoggingMiddleware>();
app.UseMiddleware<ResponseLoggingMiddleware>();

现在我只是尝试记录正文,请求记录似乎工作正常

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate requestDelegate;

    public RequestLoggingMiddleware(RequestDelegate requestDelegate)
    {
        this.requestDelegate = requestDelegate;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        HttpRequest httpRequest = httpContext.Request;
        httpRequest.EnableBuffering();

        ReadResult bodyReadResult = await httpRequest.BodyReader.ReadAsync();
        ReadOnlySequence<byte> bodyBuffer = bodyReadResult.Buffer;

        if (bodyBuffer.Length > 0)
        {
            byte[] bodyBytes = bodyBuffer.ToArray();
            string bodyText = Encoding.UTF8.GetString(bodyBytes);

            Console.WriteLine(bodyText);
        }

        // Reset
        httpRequest.Body.Seek(0, SeekOrigin.Begin);

        await requestDelegate(httpContext);
    }
}

我的响应日志中间件无权访问BodyReader。我尝试使用此代码

public class ResponseLoggingMiddleware
{
    private readonly RequestDelegate requestDelegate;

    public ResponseLoggingMiddleware(RequestDelegate requestDelegate)
    {
        this.requestDelegate = requestDelegate;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        await requestDelegate(httpContext);

        Stream responseBody = httpContext.Response.Body;

        using (StreamReader reader = new StreamReader(responseBody))
        {
            string bodyText = await reader.ReadToEndAsync();

            // Reset
            responseBody.Seek(0, SeekOrigin.Begin);

            Console.WriteLine(bodyText);
        }
    }
}

但不幸的是我得到了这个异常

System.ArgumentException:流不可读。

有人知道怎么解决吗?

【问题讨论】:

  • 是的,这是一个 ASP.NET Core Web API 项目
  • 您的异常消息中提到的 HttpResponseStream 不可读,它只是按设计编写的。根据您尝试这样做的原因 - 您可能可以使用一些技巧,例如 stackoverflow.com/q/43403941/5311735
  • 您确定您的代码是关于System.IO.Pipelines API 的吗?
  • @PavelAnikhouski 不,我的意思是我只是使用命名空间中的一些类型

标签: c# asp.net-core .net-core


【解决方案1】:

您可以使用 StreamReader 来读取请求正文。下面的代码,你可以关注。

            string body = string.Empty;
            Request.EnableRewind();
            using (var reader = new StreamReader(Request.Body))
            {
                Request.Body.Seek(0, SeekOrigin.Begin);
                body = reader.ReadToEnd();
            }

获取响应正文的方式相同。

            using (var reader = new StreamReader(Response.Body))
            {
                Response.Body.Seek(0, SeekOrigin.Begin);
                body = reader.ReadToEnd();
            }

【讨论】:

  • 感谢您的回复。不幸的是,我无法访问 EnableRewind 方法。但我使用Microsoft.AspNetCore.Http 导入了。但是我的包Microsoft.AspNetCore.Http 不知道Microsoft.AspNetCore.Http.Internal 命名空间
  • 啊,在核心 3.0 中是 EnableBuffering
  • 是的,我使用的是 .net core 2.2
  • 对不起,我得到了这个异常System.ArgumentException: Stream was not readable.
  • @OlafSvenson,你能分享你的代码吗?你试过什么?。
【解决方案2】:

基于此处接受的答案

How to read ASP.NET Core Response.Body?

我稍微修改了解决方案并让它工作。我想分享我关于如何记录每个传入请求和每个传出响应的解决方案。

如果您认为此解决方案容易出错或是否可以改进,请发表评论!

对于请求记录:

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate requestDelegate;
    private readonly ILogger<RequestLoggingMiddleware> logger;

    public RequestLoggingMiddleware(RequestDelegate requestDelegate, ILogger<RequestLoggingMiddleware> logger)
    {
        this.requestDelegate = requestDelegate;
        this.logger = logger;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        await LogRequest(httpContext.Request);
        await requestDelegate(httpContext);
    }

    private async Task LogRequest(HttpRequest httpRequest)
    {
        StringBuilder stringBuilder = new StringBuilder();

        AppendMethod(httpRequest, stringBuilder);
        AppendPath(httpRequest, stringBuilder);
        AppendContentType(httpRequest, stringBuilder);
        AppendHeaders(httpRequest, stringBuilder);
        AppendParams(httpRequest, stringBuilder);
        AppendQueries(httpRequest, stringBuilder);
        await AppendBody(httpRequest, stringBuilder);

        logger.LogTrace(stringBuilder.ToString());
    }

    private void AppendMethod(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        stringBuilder.AppendLine($"Method: {httpRequest.Method}");
    }

    private void AppendPath(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        stringBuilder.AppendLine($"Path: {httpRequest.Path.Value}");
    }

    private void AppendContentType(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        string contentType = httpRequest.ContentType;

        if (!string.IsNullOrEmpty(contentType))
        {
            stringBuilder.AppendLine($"Content type: {contentType}");
        }
    }

    private void AppendHeaders(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        AppendCollection(httpRequest.Headers, "Headers", stringBuilder);
    }

    private void AppendParams(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        AppendCollection(httpRequest.RouteValues, "Params", stringBuilder);
    }

    private void AppendQueries(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        AppendCollection(httpRequest.Query, "Queries", stringBuilder);
    }

    private void AppendCollection<TKey, TValue>(
        IEnumerable<KeyValuePair<TKey, TValue>> collection,
        string collectionName,
        StringBuilder stringBuilder)
    {
        if (collection.Any())
        {
            stringBuilder.AppendLine($"{collectionName}:");

            foreach ((TKey key, TValue value) in collection)
            {
                stringBuilder.AppendLine($"\t{key}: {value}");
            }
        }
    }

    private async Task AppendBody(HttpRequest httpRequest, StringBuilder stringBuilder)
    {
        httpRequest.EnableBuffering();

        ReadResult bodyReadResult = await httpRequest.BodyReader.ReadAsync();
        ReadOnlySequence<byte> bodyBuffer = bodyReadResult.Buffer;

        if (bodyBuffer.Length > 0)
        {
            byte[] bodyBytes = bodyBuffer.ToArray();
            string bodyText = Encoding.UTF8.GetString(bodyBytes);
            stringBuilder.AppendLine($"Body: {bodyText}");
        }

        httpRequest.Body.Seek(0, SeekOrigin.Begin);
    }
}

响应记录有点不同

public class ResponseLoggingMiddleware
{
    private readonly RequestDelegate requestDelegate;
    private readonly ILogger<RequestLoggingMiddleware> logger;

    public ResponseLoggingMiddleware(RequestDelegate requestDelegate, ILogger<RequestLoggingMiddleware> logger)
    {
        this.requestDelegate = requestDelegate;
        this.logger = logger;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        HttpResponse httpResponse = httpContext.Response;
        Stream originalBody = httpResponse.Body;

        try
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                httpResponse.Body = memoryStream;

                await requestDelegate(httpContext);
                await LogResponse(httpContext.Response, originalBody, memoryStream);
            }
        }
        finally
        {
            httpContext.Response.Body = originalBody;
        }
    }

    private async Task LogResponse(HttpResponse httpResponse, Stream originalBody, MemoryStream memoryStream)
    {
        StringBuilder stringBuilder = new StringBuilder();

        AppendStatusCode(httpResponse, stringBuilder);
        AppendContentType(httpResponse, stringBuilder);
        await AppendBody(httpResponse, stringBuilder, originalBody, memoryStream);

        logger.LogTrace(stringBuilder.ToString());
    }

    private void AppendStatusCode(HttpResponse httpResponse, StringBuilder stringBuilder)
    {
        stringBuilder.AppendLine($"Status code: {httpResponse.StatusCode}");
    }

    private void AppendContentType(HttpResponse httpResponse, StringBuilder stringBuilder)
    {
        string contentType = httpResponse.ContentType;

        if (!string.IsNullOrEmpty(contentType))
        {
            stringBuilder.AppendLine($"Content type: {contentType}");
        }
    }

    private async Task AppendBody(HttpResponse httpResponse, StringBuilder stringBuilder, Stream originalBody, MemoryStream memoryStream)
    {
        httpResponse.Body.Seek(0, SeekOrigin.Begin);

        StreamReader streamReader = new StreamReader(memoryStream);
        string bodyText = await streamReader.ReadToEndAsync();

        if (bodyText.Length > 0)
            stringBuilder.AppendLine($"Body: {bodyText}");

        httpResponse.Body.Seek(0, SeekOrigin.Begin);
        await memoryStream.CopyToAsync(originalBody);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 2018-04-03
    • 2018-01-24
    • 1970-01-01
    • 2017-10-09
    相关资源
    最近更新 更多