• .net core 打印请求和响应的内容


    实现打印请求参数和响应结果的中间件,本以为比较容易,但是花了不少时间。

    正确的代码:

        public class LogginMiddleware
        {
            private readonly RequestDelegate _next;
            private readonly ILogger _logger;
    
            public LogginMiddleware(RequestDelegate next, ILogger<LogginMiddleware> logger)
            {
                _next = next;
                _logger = logger;
            }
    
            public async Task Invoke(HttpContext httpContext)
            {
                var req = httpContext.Request;
                req.EnableBuffering();
    
                using (StreamReader requestReader = new StreamReader(req.Body, Encoding.UTF8))
                {
                    //log request
                    var bodyStr = await requestReader.ReadToEndAsync();
                    req.Body.Position = 0;
    
                    _logger.LogInformation("Url:[{url}] ", httpContext.Request.GetDisplayUrl());
                    if (!string.IsNullOrEmpty(bodyStr))
                    {
                        _logger.LogInformation("Body:[{request}]", bodyStr);
                    }
    
                    using (var buffer = new MemoryStream())
                    {
                        //replace the context response with our buffer
                        var stream = httpContext.Response.Body;
                        httpContext.Response.Body = buffer;
    
                        //invoke the rest of the pipeline
                        await _next.Invoke(httpContext);
    
                        //reset the buffer and read out the contents
                        buffer.Seek(0, SeekOrigin.Begin);
                        var reader = new StreamReader(buffer);
                        using (var bufferReader = new StreamReader(buffer))
                        {
                            string body = await bufferReader.ReadToEndAsync();
    
                            //reset to start of stream
                            buffer.Seek(0, SeekOrigin.Begin);
    
                            //copy our content to the original stream and put it back
                            await buffer.CopyToAsync(stream);
                            httpContext.Response.Body = stream;
    
                            _logger.LogInformation("Response:[{response}]", body);
                        }
                    }
                }
            }
        }
    

    无论对于requestresponse,都是Stream类型,当被读取后,内部的偏移会移动。而两者情况又有不同。

    Request

    request如果被读取后,后面的组件就无法再次读取,但是.net提供了EnableBuffering()方法允许对request重复读取。

    但是这里有一点需要注意,我原本将读取的代码提取到一个单独的方法中,把request传入读取。

    async Task<string> ReadBodyStr(HttpRequest req) {
          req.EnableBuffering();
    
          using (StreamReader requestReader = new StreamReader(req.Body, Encoding.UTF8))
          {
              var bodyStr = await requestReader.ReadToEndAsync();
              req.Body.Position = 0;
              return bodyStr;
          }
    }            
    

    这里用req.Body传入StreamReader,using结束后stream会被自动关闭,导致request也被关闭,后续的组件无法读取到任何内容。

    我调试了很久,最后发现只有写在一个方法中才能让后面的组件正确获取内容

    Response

    Response的问题在于默认的Response不支持seek,而当后面的组件开始写入Response后,写入的内容可能已经发往客户端,我这里就读不到了。所以有了SO上的这个hack方式

    即用MemoryStream替换Response中原本的Body,给后面的组件处理后,读出内容,Seek到开始位置,再写入原始的Stream中。

  • 相关阅读:
    使用JFileChooser实现在指定文件夹下批量添加根据“数字型样式”或“非数字型样式”命令的文件夹
    51Nod 1376 最长递增子序列的数量 (DP+BIT)
    POJ 2728 Desert King (最优比率树)
    UVa 11280 Flying to Fredericton (DP + Dijkstra)
    UVa 11367 Full Tank? (DP + Dijkstra)
    UVa 10269 Adventure of Super Mario (Floyd + DP + BFS)
    UVaLive 4452 The Ministers' Major Mess (TwoSat)
    UVa 11294 Wedding (TwoSat)
    HDU 3247 Resource Archiver (AC自动机+BFS+状压DP)
    HDU 5957 Query on a graph (拓扑 + bfs序 + 树剖 + 线段树)
  • 原文地址:https://www.cnblogs.com/mosakashaka/p/12609210.html
Copyright © 2020-2023  润新知