ChatGPT解决这个技术问题 Extra ChatGPT

如何查看 HttpWebRequest 类发送的原始 HTTP 请求?

我知道你们都会回答“使用像 Fiddler 这样的调试代理服务器”,但这并不是那么简单。

这是我的情况:我有一些代码在服务器上运行,在 ASP.NET 页面代码隐藏 (aspx.cs) 中,它(除其他外)建立与另一台服务器的连接,获取一些内容,然后对其进行格式化并将其返回给浏览器。

问题是另一台服务器做错了,所以我希望能够将调试标志传递到页面中(通过查询字符串,例如?debug=true),以便打印出完全原始的 HTTP请求它发送到另一台服务器,这样我就可以看到到底出了什么问题。这段代码在几个地方运行,所以我希望能够在开发、登台或生产上传递这个标志并只看到请求,而不必弄清楚生产服务器是否可以与某个存在于某处的代理服务器通信, ETC。

你会认为这样做很容易,对吧?所以我觉得我疯了之类的,但我查看了 HttpWebRequest 及其父类 WebRequest 的参考资料,但什么也没有。没办法。你会认为微软会想到这一点。最接近的是您可以访问“标题”集合,但是当我尝试它时,它省略了一些非常重要的标题,例如“内容长度” - 所以它一定是对我“撒谎”(我知道它在撒谎,因为我知道对于远程服务器返回 200 状态的事实——请求成功,它只是返回错误/不同/错误的数据)

这是要求的代码示例:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://www.whatever.com");
req.Method = ... whatever ...;
... other setup for the request ...
/* At this point we are about to send the request.
   What does the raw HTTP request look like? */
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
您可以用其他组件替换 HttpWebRequest 吗?如果是,您可以使用一些第三方 HTTP 组件,让您捕获发送的任何内容(或标头)来完成这项工作。
您是否尝试过 Firebug for firefox?它非常强大,我不知道它与 Fiddler 相比如何,但也许它有你需要的东西?
Firebug 无济于事,因为有趣的部分发生在两台服务器之间——Firebug 位于 Firefox 内部,它只能检查一台服务器和客户端之间发生的情况。
尤金,你知道任何组件吗?我考虑过实现我自己的 HttpWebRequest 版本,但这是一项繁重的工作。我不知道是否可以继承 HttpWebRequest 并以这种方式访问任何有用的属性。
吉姆,我添加了一个代码示例。就我而言,它是一个 POST,我正在调用 GetRequestStream,但我希望能够对任何类型的请求(GET 或 POST)执行此操作。请注意,GetRequestStream 只给我内容/正文,而不是标题,实际上,如果您尝试为 GET 请求调用 GetRequestStream,它将引发异常。

M
Michael

我意识到这是一个老问题。 @feroze's answer 说明了要做什么,但没有详细说明如何设置 System.Net 跟踪来实现它。

由于这个问题是我对该主题的查询的第一个谷歌结果,而且我们都是忙碌的人,我想我会让你们不必去寻找这些信息。

System.Web 对于调试 HttpWebRequest 非常强大,可以使用 web.config 轻松设置:

<configuration>
    <system.diagnostics>

        <trace autoflush="true" /> 

        <sources>
            <source name="System.Net" maxdatasize="1024">
                <listeners>
                    <add name="MyTraceFile"/>
                    <add name="MyConsole"/>
                </listeners>
            </source>
        </sources>

        <sharedListeners>
            <add
              name="MyTraceFile"
              type="System.Diagnostics.TextWriterTraceListener"
              initializeData="System.Net.trace.log" />
                <add name="MyConsole" type="System.Diagnostics.ConsoleTraceListener" />
        </sharedListeners>

        <switches>
            <add name="System.Net" value="Verbose" />
        </switches>

    </system.diagnostics>
</configuration>

在代码中添加一个简单的 HttpWebRequest,并在 Visual Studio 中以调试模式运行,调试控制台中将显示以下信息:

System.Net Verbose: 0 : [6596] WebRequest::Create(https://example.com/service.asmx)
System.Net Verbose: 0 : [6596] HttpWebRequest#62063506::HttpWebRequest(https://example.com/service.asmx#11234)
System.Net Information: 0 : [6596] RAS supported: True
System.Net Verbose: 0 : [6596] Exiting HttpWebRequest#11234::HttpWebRequest() 
System.Net Verbose: 0 : [6596] Exiting WebRequest::Create()     -> HttpWebRequest#11234
System.Net Verbose: 0 : [6596] HttpWebRequest#11234 ::GetRequestStream()
System.Net Verbose: 0 : [6596] ServicePoint#11234 ::ServicePoint(example.com:443)
System.Net Information: 0 : [6596] Associating HttpWebRequest#11234with ServicePoint#11234
System.Net Information: 0 : [6596] Associating Connection#11234 with HttpWebRequest#11234 
System.Net Information: 0 : [6596] Connection#11234 - Created connection from x.x.x.x:xx to x.x.x.x:xx.
System.Net Information: 0 : [6596] TlsStream#11234 ::.ctor(host=example.com, #certs=0)
System.Net Information: 0 : [6596] Associating HttpWebRequest#11234 with ConnectStream#11234 
System.Net Verbose: 0 : [6596] Exiting HttpWebRequest#11234 ::GetRequestStream()    -> ConnectStream#11234 
System.Net Verbose: 0 : [6596] ConnectStream#7740977::Write()
System.Net Verbose: 0 : [6596] Data from ConnectStream#11234::Write
System.Net Verbose: 0 : [6596] 00000000 : 3C 73 6F 61 70 3A 45 6E-76 65 6C 6F 70 65 0D 0A : <soap:Envelope..
...etc

我发现这在尝试找出 Web 服务客户端错误的原因时特别有用。原来我错过了一个标题。


哇。这个小实用程序正是我所需要的。我有一个控制台程序发出运行良好的发布请求,但是一个 ASP.NET WebForm 应用程序因相同的请求而失败。这个实用程序向我展示了我需要的原始 POST 请求的不同之处!只需根据需要将其添加到 web.config 和 app.config 文件中即可。谢谢神井!
比设置/使用 Fiddler 或 Wireshark 更方便。
如果您希望这样做,有一些时间戳可能会有所帮助 - 有关详细信息,请参阅此答案和评论:stackoverflow.com/a/867328/1880663 简短版本是您应该在配置文件中添加类似这样的内容:<add name="MyTraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="System.Net.trace.log" traceOutputOptions="DateTime" />
B
Bill the Lizard

您可以使用 System.Net 跟踪机制来查看网络上发送的原始 HTTP 请求。您还可以将自己的跟踪侦听器添加到进程中。


我没试过,这看起来是个不错的选择。谢谢!
由于某种原因对我不起作用,尽管这似乎是最好的答案(我不会取消复选标记)。在此处查看我的帖子:stackoverflow.com/questions/3822941/…
嗯.. 当然,这一直对我有用 - 我总是做控制台应用程序。您是否确保向 ASP.NET 身份(帐户)授予对要写入跟踪输出的文件/目录的写入权限?
对我来说效果很好 - 使用控制台应用程序。是一个拼写错误导致它失败。谢谢!
这种答案应该包括说明。
O
Oded

您可以使用像 wireshark 这样的网络流量嗅探器。

这不是调试代理,但会嗅探所有流量并让您查看原始请求/响应。


如果这就像我过去在家中安装的典型数据包嗅探器,那很可能需要我在工作中没有的管理员访问级别。我无法在办公室使用它,因为简单地说,我可以阅读老板的电子邮件。具有讽刺意味的是,如果我可以将桌面远程访问生产服务器,那么获得管理员访问权限可能会更容易,但问题是我根本无法访问它们,甚至无法推送文件(另一家公司这样做)。
我只会使用我上面概述的技术 - 使用 web.config 文件在您的 appdomain 中安装 Tracelistener,然后让 tracelistener 将调试 spew 写入本地磁盘,或写入 webpate,然后呈现给客户端。
我发现 Fiddler (fiddler2.com) 是解决这个问题的一个非常简单的方法。
请记住,Wireshark 不会捕获 localhost 流量。而是使用名为 RawCap 的工具将 localhost 流量捕获到文件,然后使用 Wireshark 对其进行分析。
e
eeeeaaii

在这里回答我自己的问题,因为我想到了另一种方法。基本上这个想法是——你将 HttpWebRequest 重新指向一个记录传入的原始 HTTP 请求的页面。换句话说,根据此论坛帖子设置自定义 HTTP 处理程序:

http://forums.asp.net/t/353955.aspx

然后只更改 HttpWebRequest 中的 URL 以指向这个新端点,但保持请求的所有其他元素相同。将结果写入文件或其他东西,你就可以了。


j
jhilgeman

我知道这是一个老问题,但我处于无法控制应用程序配置文件的困境中,因此我需要一种简单的方法来通过代码启用跟踪,然后轻松访问原始请求/响应数据事件。所以我把这个自定义类 HttpRawTraceListener 放在一起,它可能对我所在位置的其他人有用:

https://github.com/jhilgeman/HttpRawTraceListener/blob/master/HttpRawTraceListener.cs

它的设计就像将文件添加到项目中一样简单,然后调用:

System.Diagnostics.HttpRawTraceListener.Initialize();

...开始跟踪。从那里,请求/响应将从跟踪消息中解析出来,然后通过 System.Diagnostics.HttpRawTraceListener.FinishedCommunication 事件提供。

它可能不是 100% 适合所有场景(例如,它不是代理,因此它不会捕获来自浏览器的 Web 请求),但它可以很好地捕获对 Web 服务的 HttpWebRequests 请求/响应,并且它可能如果您需要这样的东西,这是一个很好的起点。


这正是我需要的,但我无法让它工作。我在控制台应用程序中有静态主要方法。我 initialized() HttpRawTraceListener 并设置了 FinishedCommunication 但是当我执行 HttpClient().PostAsync() 时没有捕获任何内容:/ 我正在使用 .net framework 4.6.1
使用 HttpClient.PostAsync 将导致响应上的缓冲读取/延迟结果,这不会是 System.Net 日志记录的一部分,因此最终结果是侦听器类将无法按顺序看到完整的响应完成通讯。
但是,我可能会更新侦听器以仅侦听该场景并完成通信,这样您就可以看到除原始响应主体之外的所有内容。
喜欢这个想法,并在许多地方看到它。但是,当我运行它时,它会通过初始化方法引发空引用异常。在 .net 4.5 框架上,内部 system.net.logging 类型加载正常,但找不到任何名为:s_LoggingInitialized、s_LoggingEnabled 的字段,也没有找到属性“Web”。
M
Mroczny Arturek

我建议您下载 Telerik Fiddler 以捕获传入/传出流量。

这里是一个简单的例子,如何通过该工具来做到这一点:

确保捕获流量已启用:打开浏览器并刷新页面,或者只是通过 HTTP 客户端发送请求。切换到 Fiddler 后,您应该会看到您的请求:在顶部尝试导航“Raw”选项卡。在下面的窗口中是您的原始请求


如果您有密钥,是否可以查看 HTTPS 请求并对其进行解密?
您能否检查一下:docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS 或尝试 google:“telerik fiddler capture https 流量”。
C
Community

另一个建议。 Implement your own web proxy,并将您的请求设置为与 WebRequest.Proxy 一起使用。然后您应该能够从代理实例中提取流量。

编辑:更新链接。


是的,我想过这样做,这似乎是唯一的方法。但它引入了很多复杂性。假设我实现了一个与站点位于同一服务器上的 Web 代理。它对输出有什么作用?将其记录到文件中?鉴于我无权访问服务器,有没有办法连接到代理并查看日志?我认为在生产服务器上设置它是困难的或不可能的,因为它需要打开一个新端口来引导代理流量,而管理员不允许这样做。
好吧,代理可以拒绝所有不是来自本地机器的请求。您无需向外界开放端口。您可以仅在#IF DEBUG 部分执行所有这些操作或仅通过代理请求。让它记录到事件日志或文件中,然后让生产向您发送日志。除了要求他们在生产机器上为您运行 Fiddler 之外,这是您能做的最好的事情。就个人而言,我会推动这个(他们运行 Fiddler),老实说,如果这意味着节省时间和金钱,而不是认真地滚动你自己的进程内代理记录器。
此外,您能否只使用一些虚拟机设置模拟您的生产环境的测试服务器?问题真的只限于这台机器吗?
您不会相信维护这些服务器所涉及的官僚作风……我认为 system.net 跟踪可能是解决此问题的最佳方式。
y
yfeldblum

您说您认为 .NET 对您撒谎,而您给出的具体示例是 HTTP 响应中缺少标头 Content-Length

但是 HTTP 响应不需要标头 Content-Length。事实上,如果响应的主体是动态的,并且如果事先不知道它的长度,那么 Content-Length 标头很可能会被省略!


我说的是请求,而不是响应。这是我进行的测试:我运行了程序,它发出了一个 http 请求并得到了响应。然后,我根据 .NET 告诉我它正在发送的确切信息(打印出 HttpWebRequest.Headers、HttpWebRequest.Method 等)手工制作了一个请求(在 fiddler 中)。具体来说,此请求省略了 Content-Length。但是服务器返回一个错误,指出 Content-Length 是必需的(这是有道理的,因为它是一个 POST 请求)。因此,我无法信任 .NET 报告的内容。
ps 同样,当我在具有两个不同版本的 .NET 的两台服务器上运行时,完全相同的 .NET 代码报告了一组不同的标头。现在,也许这两个版本的 .NET 实际上产生了不同的标头 IDK。但这让我很怀疑,我想要一个原始转储。
w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 - Content-Length 在许多情况下都不能给出,包括在使用分块传输编码时。目标服务器是否支持 HTTP/1.1?
好吧,服务器配置为在缺少 Content-Length 时返回 411 错误(通过在 fiddler 中手工制作请求对此进行了测试)。所以重点是,当我实例化一个 HttpWebRequest 并设置它,然后打印出标题时,它不包含 Content-Length 作为标题。但如果这是真的,那么当我在 httpWebRequest 上调用 GetResponse 时会得到 411——但这不是我得到的错误。它以 200 成功并给了我错误的数据(另一个问题)。因此,.NET 在标题上撒谎。