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

.NET Core中获取外部API请求体并记录至Application Insights的方法

最优实现方案:记录自身API及外部API的请求体到Application Insights

一、核心思路

要同时记录自身API的入站请求和调用外部API的出站请求,需分两部分处理:

  1. 入站请求:沿用现有代码逻辑,通过HttpContext读取请求体
  2. 出站请求:拦截HTTP客户端的请求流程,在发送前捕获请求体和URL信息

二、具体实现步骤

1. 自定义HTTP客户端消息处理器(拦截外部API请求)

创建继承自DelegatingHandler的处理器,在发送请求前捕获外部API的URL和请求体,再记录到Application Insights:

public class LoggingHandler : DelegatingHandler
{
    private readonly ILogger<LoggingHandler> _logger;
    private readonly RecyclableMemoryStreamManager _streamManager;

    public LoggingHandler(ILogger<LoggingHandler> logger, RecyclableMemoryStreamManager streamManager)
    {
        _logger = logger;
        _streamManager = streamManager;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string requestBody = string.Empty;
        if (request.Content != null)
        {
            // 复制请求流以便读取,同时保留原始流供后续发送使用
            var originalStream = await request.Content.ReadAsStreamAsync(cancellationToken);
            originalStream.Position = 0;
            
            using (var memoryStream = _streamManager.GetStream())
            {
                await originalStream.CopyToAsync(memoryStream, cancellationToken);
                memoryStream.Position = 0;
                requestBody = new StreamReader(memoryStream).ReadToEnd();
                
                // 重置原始流位置,确保请求能正常发送
                originalStream.Position = 0;
                request.Content = new StreamContent(originalStream);
            }
        }

        // 记录外部API请求信息到Application Insights
        _logger.LogInformation("External API Request - URL: {Url}, Body: {RequestBody}", request.RequestUri, requestBody);

        return await base.SendAsync(request, cancellationToken);
    }
}

2. 注册自定义处理器到HTTP客户端

在Program.cs(或Startup.cs)中注册处理器,确保所有调用外部API的HTTP客户端都使用该拦截逻辑:

builder.Services.AddSingleton<RecyclableMemoryStreamManager>();
builder.Services.AddTransient<LoggingHandler>();

// 注册带日志处理器的HTTP客户端
builder.Services.AddHttpClient("ExternalApiClient")
    .AddHttpMessageHandler<LoggingHandler>();

3. 优化现有入站请求日志逻辑

调整现有代码,确保读取请求体后不影响后续中间件处理,同时完善日志内容:

private async Task LogRequest(HttpContext context, string correlationID)              
{
    context.Request.EnableBuffering();

    aiLogger.LogPageView(context.Request.Path.Value);

    string requestBody = string.Empty;
    using (var requestStream = _recyclableMemoryStreamManager.GetStream())
    {
        await context.Request.Body.CopyToAsync(requestStream);
        requestStream.Position = 0;
        requestBody = new StreamReader(requestStream).ReadToEnd();
        
        // 重置请求流位置,确保后续流程能正常读取
        context.Request.Body.Position = 0;
    }

    // 记录自身API请求信息
    aiLogger.LogInformation("Inbound API Request - Path: {Path}, Body: {RequestBody}, CorrelationID: {CorrelationID}", 
        context.Request.Path, requestBody, correlationID);
}

4. 关联追踪ID(Correlation ID)

为方便在Application Insights中排查问题,确保入站和出站请求使用同一个CorrelationID:

  • 在入站请求日志中生成或获取CorrelationID,存入HttpContext.Items
  • 在LoggingHandler中从HttpContext获取该ID,一并记录到日志

三、关键注意事项

  • 流重置:读取入站/出站请求流后,必须重置流的位置,否则后续流程无法读取内容
  • 内存管理:使用RecyclableMemoryStreamManager避免频繁创建内存流带来的性能损耗
  • 敏感信息过滤:若请求体包含密码、Token等敏感数据,需先脱敏再记录,防止数据泄露

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:45:34