如何记录传出的 HttpClient 请求?

Posted

技术标签:

【中文标题】如何记录传出的 HttpClient 请求?【英文标题】:How to log outgoing HttpClient request? 【发布时间】:2020-10-27 16:52:20 【问题描述】:

我想连接到 REST Api,但无论我如何构建请求,它都会不断返回 status code 400 (Bad Request)

HttpResponseMessage response = client.PostAsync(url, content).Result;

response.EnsureSuccessStatusCode();

我的问题是,如何调试我的https 请求到服务器?我想看看我的 HTTP 请求是什么样子的。

我尝试使用DiagnosticSource 类,因此我创建了Observer 类并为所有听众订阅它。

观察者

class Observer : IObserver<DiagnosticListener>
    
        public void OnCompleted()
        
            throw new NotImplementedException();
        

        public void OnError(Exception error)
        
            throw new NotImplementedException();
        

        public void OnNext(DiagnosticListener value)
        
            if (value.Name == "HttpHandlerDiagnosticListener")
            
                value.Subscribe(new HttpClientObserver());
            
        
    

HttpClientObserver

 class HttpClientObserver : IObserver<KeyValuePair<string, object>>
        
            public void OnCompleted()
            
                throw new NotImplementedException();
            
    
            public void OnError(Exception error)
            
                throw new NotImplementedException();
            
    
            public void OnNext(KeyValuePair<string, object> value)
            
                throw new NotImplementedException();
            
        

主要

static void Main(string[] args)
        
            DiagnosticListener.AllListeners.Subscribe(new Diagnostic.Observer());

            // execute HttpClient methods do not throw any event to Observer

但是没有捕获到任何事件。我错过了什么,HttpClient 是否支持DiagnosticSource(我如何识别哪些课程?)。我还可以使用什么其他解决方案?

【问题讨论】:

如果您不是在寻找永久固定装置,而只是为了调试此问题,您可以使用 Fiddler 之类的工具来捕获网络流量并查看所有详细信息。 感谢您的提示,但我无法使用这些工具。无论如何,Fiddler 可以检查https 请求吗? 是的,可以。也是邮递员的拦截器。 Burp Suite 还可以跟踪 http/https 流量。 你需要等待 PostAsync。例如 HttpResponseMessage response = await client.PostAsync(url, content); 【参考方案1】:

当您订阅侦听器时,您将创建一个类的新实例。您应该做的是创建一个私有只读实例。 DiagnosticListener 仅限于捕获 HTTP 客户端请求的开始和结束。

下面是一个基本的例子,(代码略有重构)

public static async Task Main(string[] args)

    var observer = new HttpClientGlobalListener();

    using (var subscription = DiagnosticListener.AllListeners.Subscribe(observer))
    
        var results = await GetMyResultsAsync();
        Console.WriteLine(results);
    


public static async Task<string> GetMyResultsAsync()

    var queryString = new StringContent("");

    using (HttpClient client = new HttpClient())
    
        HttpResponseMessage response = await client.PostAsync(new Uri("https://example/"), queryString);
        //var json = JsonConvert.SerializeObject(response); // You could log response before raising error with "EnsureSuccessStatusCode".

        response.EnsureSuccessStatusCode();
        string responseBody = await response.Content.ReadAsStringAsync();
        return responseBody;
    


public class HttpClientGlobalListener : IObserver<DiagnosticListener>

    private readonly HttpClientInterceptor _interceptor = new HttpClientInterceptor();

    public void OnCompleted()  

    public void OnError(Exception error)  

    public void OnNext(DiagnosticListener listener)
    
        listener.Subscribe(_interceptor);
    


public class HttpClientInterceptor : IObserver<KeyValuePair<string, object>>

    public void OnCompleted()  

    public void OnError(Exception error)  

    public void OnNext(KeyValuePair<string, object> value)
    
        if (value.Key == "System.Net.Http.Desktop.HttpRequestOut.Start")
        
            var requestObj = JsonConvert.SerializeObject(value.Value);
            Debug.WriteLine($"Request: requestObj");
        
        else if (value.Key == "System.Net.Http.Desktop.HttpRequestOut.Stop")
        
            var requestObj = JsonConvert.SerializeObject(value.Value);
            Debug.WriteLine($"Response: requestObj");
        
    

【讨论】:

谢谢,它可以工作 :-) 我现在可以捕获 Request 对象了。但是,我不知道如何将对象转换为我真正发送的raw HTTP Request,或者如何至少显示我发送的数据(HttpContent 对象)以及raw HTTP Request 中的数据在哪里?跨度> “value.Value”包含 HTTP 请求。然而,它被包裹在一个动态对象中。我不确定如何查询它。通过使用 Json Serialize,您可以将整个内容存储为字符串并读取它。一个 hacky 解决方案(理论上)是,一旦转换为字符串,您可以删除开始和结束大括号并将其反序列化为 HttpRequest 对象。 我把value.Value保存到了json文件,没关系。但是json中并没有包含太多的信息,甚至连请求是get或者post等都不包含信息。 不幸的是,json 序列化程序值无法输出所有内容。您可以在调试器中看到所有值。但是我不知道如何查询动态对象。我建议发布另一个问题,特别是“如何将 Value.Value 从对象 f__AnonymousType1 转换为 Value.Value.Request

以上是关于如何记录传出的 HttpClient 请求?的主要内容,如果未能解决你的问题,请参考以下文章

.NET HttpClient:如何动态设置请求方法?

c#:如何使用 httpclient 发布异步请求并获取流?

新手求助,Arduino联网后,如何回应HttpClient的GET请求

如何在 .net Core API 项目中跨多个线程限制对 HttpClient 的所有传出异步调用

编码请求正文

区分 HttpClient 请求失败类型