zoukankan      html  css  js  c++  java
  • .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中。

  • 相关阅读:
    bzoj4423 [AMPPZ2013]Bytehattan
    bzoj3643 Phi的反函数
    hdu1024 Max Sum Plus Plus的另一种解法
    hdu1024 Max Sum Plus Plus
    bzoj3638 Cf172 k-Maximum Subsequence Sum
    bzoj3620 似乎在梦中见过的样子
    bzoj3667 Rabin-Miller算法
    bzoj3680 吊打XXX
    阿里Linux Shell脚本面试25个经典问答
    编程面试的10大算法概念汇总
  • 原文地址:https://www.cnblogs.com/mosakashaka/p/12609210.html
Copyright © 2011-2022 走看看