.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中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM