如何阅读HttpResponse正文?

奥拉夫·斯文森(Olaf Svenson)

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

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:流不可读。

有人知道如何解决吗?

奥拉夫·斯文森(Olaf Svenson)

根据此处的正确答案

如何阅读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);
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章