You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Asp.Net Web Api如何在ActionFilter中捕获GET/POST请求日志

解决ASP.NET Web API ActionFilter同时捕获GET/POST请求内容的问题

我来帮你搞定这个日志统一记录的问题!核心点在于GET和POST请求的参数存储位置不一样:GET的参数在URL的QueryString里,而POST的在请求Body中,我们需要在ActionFilter里分别处理这两种情况。

完整的CustomLogAttribute实现

public class CustomLogAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        // 从Request.Properties中获取已授权的用户和AccessToken
        if (!actionContext.Request.Properties.TryGetValue("User", out var userObj) || userObj is not User user)
        {
            // 可以在这里记录用户未找到的警告日志
            return;
        }
        var serviceTicket = actionContext.Request.Properties.TryGetValue("AccessToken", out var ticketObj) 
            ? ticketObj.ToString() 
            : string.Empty;

        string requestContent = string.Empty;
        var requestMethod = actionContext.Request.Method.Method.ToUpperInvariant();

        if (requestMethod == "GET")
        {
            // 处理GET请求:解析QueryString参数
            var queryParams = actionContext.Request.RequestUri.ParseQueryString();
            requestContent = string.Join("&", queryParams.AllKeys.Select(key => $"{Uri.EscapeDataString(key)}={Uri.EscapeDataString(queryParams[key])}"));
        }
        else
        {
            // 处理POST/PUT/DELETE等带请求体的请求
            try
            {
                // 异步读取请求体,避免潜在死锁
                requestContent = actionContext.Request.Content.ReadAsStringAsync().ConfigureAwait(false).GetAwaiter().GetResult();
                
                // 关键:读取后重置流位置,确保后续控制器能正常获取请求体
                if (actionContext.Request.Properties.TryGetValue("MS_HttpContext", out var contextObj) && contextObj is HttpContextBase httpContext)
                {
                    httpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);
                }
            }
            catch (Exception ex)
            {
                // 记录读取请求体失败的异常
                Log.WriteError($"读取请求体失败: {ex.Message}");
            }
        }

        // 记录开始日志(和你原来的逻辑一致)
        Log.Write(user.Id, "started", serviceTicket);
        // 记录详细请求日志
        var methodName = actionContext.ActionDescriptor.ActionName;
        Log.WriteDetail(requestContent, user.Id, methodName, serviceTicket);

        base.OnActionExecuting(actionContext);
    }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        // 记录结束日志(放在Action执行后,和原逻辑匹配)
        if (actionExecutedContext.Request.Properties.TryGetValue("User", out var userObj) && userObj is User user)
        {
            var serviceTicket = actionExecutedContext.Request.Properties.TryGetValue("AccessToken", out var ticketObj) 
                ? ticketObj.ToString() 
                : string.Empty;
            Log.Write(user.Id, "finished", serviceTicket);
        }

        base.OnActionExecuted(actionExecutedContext);
    }
}

关键细节说明

  1. GET请求参数处理:

    • 通过RequestUri.ParseQueryString()解析URL中的查询参数,然后拼接成类似key1=value1&key2=value2的字符串。
    • 使用Uri.EscapeDataString()对参数值进行编码,避免特殊字符导致日志格式混乱。
  2. POST请求体处理:

    • 读取请求体后必须重置InputStream的位置到开头,否则后续的控制器方法(比如使用[FromBody]绑定参数)会读取不到内容,这是很多人容易忽略的坑!
    • 用ConfigureAwait(false).GetAwaiter().GetResult()替代直接调用.Result,减少异步操作的死锁风险。
  3. 日志时机拆分:

    • 把started日志放在OnActionExecuting(接口执行前),finished日志放在OnActionExecuted(接口执行后),完全匹配你原来每个接口里的日志顺序。
  4. 健壮性优化:

    • 对User和AccessToken的获取做了空值判断,避免空引用异常。
    • 捕获读取请求体的异常,防止日志逻辑影响主业务流程。

使用方式

你可以选择两种方式应用这个Filter:

  • 全局注册(所有接口都生效):在WebApiConfig.cs中添加
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new CustomLogAttribute());
        // 其他WebAPI配置...
    }
    
  • 局部应用(指定控制器/接口生效):在控制器或接口方法上添加特性
    [CustomAuthorization]
    [CustomLog]
    public class ContentController : BaseApiController
    {
        // 你的接口方法...
    }
    

额外注意事项

  • 如果有敏感参数(比如密码、手机号),记得在日志记录前做脱敏处理,不要直接写入日志。
  • 对于大文件上传的POST请求,可以考虑跳过日志记录,避免占用过多日志存储空间。
  • 其他HTTP方法(PUT/DELETE等)的参数处理逻辑已经包含在代码中,不需要额外修改。

内容的提问来源于stack exchange,提问作者enginocal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:41:55