zoukankan      html  css  js  c++  java
  • ASP.NET Core 入门(2)(WebApi接口请求日志 Request和Response)

    以前 .NET Framework WebApi 记录接口访问日志,一般是通过Filter的方式进行拦截,通过重写ActionFilterAttribute的OnActionExecuting实现拦截记录Request内容,通过重写OnActionExecuted实现拦截记录Response内容,具体实现代码就不贴了。这篇简单介绍.Net Core WebApi 下通过中间件的拦截方式记录接口访问日志,关键部分是通过读取获取 Request.Body 时需要开启 Request.EnableRewind () 启用倒带功能;读取 Response.Body 时需要用到的技巧,详细看代码。该例子中我使用的日志组件是Log4Net,获取到的信息通过Log4Net保存到本地文件。

    创建日志类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace DYDGame.Web.Host
    {
        public class RequestResponseLog
        {
            public string Url {get;set;}
            public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
            public string Method { get; set; }
            public string RequestBody { get; set; }
            public string ResponseBody  { get; set; }
            public DateTime ExcuteStartTime { get; set; }
            public DateTime ExcuteEndTime { get; set; }
            public override string ToString()
            {
                string headers = "[" + string.Join(",", this.Headers.Select(i => "{" + $""{i.Key}":"{i.Value}"" + "}")) + "]";
                return $"Url: {this.Url},
    Headers: {headers},
    Method: {this.Method},
    RequestBody: {this.RequestBody},
    ResponseBody: {this.ResponseBody},
    ExcuteStartTime: {this.ExcuteStartTime.ToString("yyyy-MM-dd HH:mm:ss.fff")},
    ExcuteStartTime: {this.ExcuteEndTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}";
            }
        }
    }

    创建记录接口日志中间件 Middleware

    using System;
    using System.Collections.Specialized;
    using System.IO;
    using System.Linq;
    using System.Net.Http;
    using System.Threading.Tasks;
    using System.Text;
    using System.Threading;
    using DYDGame.Utility;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Http.Internal;
    using Microsoft.AspNetCore.Mvc.Formatters;
    using Microsoft.AspNetCore.WebUtilities;
    using Microsoft.Extensions.Logging;
    
    namespace DYDGame.Web.Host {
        public class RequestResponseLoggingMiddleware {
            private readonly RequestDelegate _next;
            private RequestResponseLog _logInfo;
    
            public RequestResponseLoggingMiddleware (RequestDelegate next) {
                _next = next;
            }
    
            public async Task Invoke (HttpContext context) {
                _logInfo = new RequestResponseLog ();
    
                HttpRequest request = context.Request;
                _logInfo.Url = request.Path.ToString ();
                _logInfo.Headers = request.Headers.ToDictionary (k => k.Key, v => string.Join (";", v.Value.ToList ()));
                _logInfo.Method = request.Method;
                _logInfo.ExcuteStartTime = DateTime.Now;
    
                //获取request.Body内容
                if (request.Method.ToLower ().Equals ("post")) {
    
                    request.EnableRewind (); //启用倒带功能,就可以让 Request.Body 可以再次读取
    
                    Stream stream = request.Body;
                    byte[] buffer = new byte[request.ContentLength.Value];
                    stream.Read (buffer, 0, buffer.Length);
                    _logInfo.RequestBody = Encoding.UTF8.GetString (buffer);
    
                    request.Body.Position = 0;
                    
                } else if (request.Method.ToLower ().Equals ("get")) {
                    _logInfo.RequestBody = request.QueryString.Value;
                }
    
                //获取Response.Body内容
                var originalBodyStream = context.Response.Body;
    
                using (var responseBody = new MemoryStream ()) {
                    context.Response.Body = responseBody;
    
                    await _next (context);
    
                    _logInfo.ResponseBody = await FormatResponse (context.Response);
                    _logInfo.ExcuteEndTime = DateTime.Now;
                    Log4Net.LogInfo ($"VisitLog: {_logInfo.ToString()}");
    
                    await responseBody.CopyToAsync (originalBodyStream);
                }
            }
    
            private async Task<string> FormatResponse (HttpResponse response) {
                response.Body.Seek (0, SeekOrigin.Begin);
                var text = await new StreamReader (response.Body).ReadToEndAsync ();
                response.Body.Seek (0, SeekOrigin.Begin);
    
                return text;
            }
        }
    
        public static class RequestResponseLoggingMiddlewareExtensions {
            public static IApplicationBuilder UseRequestResponseLogging (this IApplicationBuilder builder) {
                return builder.UseMiddleware<RequestResponseLoggingMiddleware> ();
            }
        }
    }

    把中间件添加到管道中 Pipeline

    在 Startup.cs 添加
            public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
                if (env.IsDevelopment ()) {
                    app.UseDeveloperExceptionPage ();
                } else {
                    app.UseHsts ();
                }
    
                loggerFactory.AddLog4Net ();
                app.UseRequestResponseLogging();
                
                // app.UseHttpsRedirection();
                app.UseMvc ();
            }

     

  • 相关阅读:
    Vue整合nginx:(1)开发环境npm run dev下,通过nginx解决前后端分离造成的跨域问题
    SpringBoot 整合 ActiveMq
    SpringBoot 整合 slf4j 日志打印
    Java 抽象类的简单使用
    MongoDB基本使用
    node.js修改全局安装文件路径
    Vue + iview框架,搭建项目遇到的相关问题记录
    ThinkPHP重写路由,掩藏public/index.php
    thinkPhP + Apache + PHPstorm整合框架
    Ionic3,装饰器(@Input、@ViewChild)以及使用 Events 实现数据回调中的相关用法(五)
  • 原文地址:https://www.cnblogs.com/wybin6412/p/10944077.html
Copyright © 2011-2022 走看看