C# HttpClient 的使用

介绍个 HTTP Client 中常用于记录请求以及响应的中间建:System.Net.Http.DelegatingHandler 文档 ,不废话直接看代码

声明:全篇基于 .NET 7 编写


点击查看代码
public sealed class LoggingHandler : DelegatingHandler
{
    public LoggingHandler() : base()
    {
    }

    public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler)
    {

    }
    /// <summary>
    /// 同步请求拦截器
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        StringBuilder logBuilder = new(Environment.NewLine);
        Uri? uri = request.RequestUri;
        logBuilder.AppendLine($"\t== request uri: {uri} at {DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}");
        logBuilder.AppendLine($"\t=- request method: {request.Method}");
        logBuilder.AppendLine($"\t=- request headers: {request.Headers.IObjectToJson()}");
        // 仅记录request.Content 是StringContent 的请求参数
        string requestContent = "";
        if (request.Content.GetType() == typeof(StringContent))
        {
            requestContent = request.Content.ReadAsStringAsync().Result;
        }
        logBuilder.AppendLine($"\t=@ request body: {requestContent}");
        HttpResponseMessage responseMessage = base.Send(request, cancellationToken);
        logBuilder.AppendLine($"\t=+ response headers: {responseMessage.Headers.IObjectToJson()}");
        if (!responseMessage.IsSuccessStatusCode)
        {
            string responseString = $"异常:{responseMessage.StatusCode}";
            // 非空时,写入响应异常信息
            logBuilder.Append($"\t=~ response error result: {responseString}");
        }
        // 日志记录,可替换为其他日志记录方式
        Log4Helper.WriteApiRequest(logBuilder.ToString(), callerMemberName);
        return responseMessage;
    }
    /// <summary>
    /// 异步请求拦截器
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        StringBuilder logBuilder = new(Environment.NewLine);
        Uri? uri = request.RequestUri;
        logBuilder.AppendLine($"\t== async request uri: {uri} at {DateTime.Now:G}");
        logBuilder.AppendLine($"\t=- async request headers: {request.Headers.IObjectToJson()}");
        // 非json 请求,不记录请求 body
        string requestContent = "";
        if (request.Content?.GetType() == typeof(StringContent))
        {
            requestContent = request.Content.ReadAsStringAsync().Result;
        }

        logBuilder.AppendLine($"\t=@ request body: {requestContent}");
        // 添加 .ConfigureAwait(false) 避免同步线程上下文
        HttpResponseMessage responseMessage = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

        logBuilder.AppendLine($"\t=+ async response headers: {responseMessage.Headers.IObjectToJson()}");
        if (!responseMessage.IsSuccessStatusCode)
        {
            string responseString = $"异常:{responseMessage.StatusCode}";
            // 非空时,写入响应异常信息
            logBuilder.Append($"\t=~ response error result: {responseString}");
        }

        Log4Helper.WriteApiRequest(logBuilder.ToString());
        return responseMessage;
    }
}

示例中 LoggingHandler 继承自 System.Net.Http.DelegatingHandler

从上往下看,可以看到构造函数包含一个无参构造函数,以及一个有 HttpMessageHandler 的 构造函数,
在发送请求的顺序上来看,通常情况下 LoggingHandler 是作为最终的handler使用,
所以需要将内部handler传入,

使用(此处使用 直接 new 一个 新的HttpClient 实际情况按需处理):

点击查看代码
public sealed class HttpHelper
{
    private static readonly HttpMessageHandler handler = new HttpClientHandler()
    {
        Proxy = null,
        AutomaticDecompression = DecompressionMethods.GZip,
        SslProtocols =
            System.Security.Authentication.SslProtocols.Tls
            | System.Security.Authentication.SslProtocols.Tls12
            | System.Security.Authentication.SslProtocols.Tls13
    };
    protected static readonly HttpMessageHandler loggerHandler = new LoggingHandler(handler);

    HttpClient newhttpClient = new(handler: loggerHandler, disposeHandler: false)
    {
        BaseAddress = new Uri(Host),
        // 设置超时时间
        Timeout = new TimeSpan(TimeSpan.TicksPerMillisecond * TimeoutInMilliSeconds),
    };
}

posted @   wolfife  阅读(562)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示