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


70

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

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

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

您会认为这样做很容易,对吧?所以我觉得自己很疯狂,但是我看了HttpWebRequest及其父类WebRequest的引用,但没有。没办法 您可能会认为Microsoft会想到这一点。最接近的事情是您可以访问“标头”集合,但是当我尝试它时,它省略了一些非常重要的标头,例如“内容长度”-因此它必须对我“说谎”(我知道它在说谎,因为我知道对于远程服务器正在返回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();

1
是否可以用其他组件替换HttpWebRequest?如果是,则可以使用一些第三方HTTP组件,该组件可让您捕获发送的所有内容(或标头)来完成此工作。
Eugene Mayevski'Callback

您是否尝试过Firebug的Firebug?它非常强大,我不知道它与Fiddler相比如何,但是也许它具有您所需要的?
格雷厄姆,2010年

8
Firebug不会帮上忙,因为有趣的部分发生在两台服务器之间-Firebug位于Firefox内部,并且它只能检查一台服务器与客户端之间发生的情况。
tdammers

尤金,您知道任何成分吗?我考虑过实现自己的HttpWebRequest版本,但这是一项艰巨的工作。我不知道是否可以继承HttpWebRequest并以这种方式访问​​任何有用的属性。
eeeeaaii 2010年

2
吉姆,我添加了一个代码示例。就我而言,它是一个POST,我正在调用GetRequestStream,但我希望能够对任何类型的请求(GET或POST)执行此操作。请注意,GetRequestStream仅提供内容/正文,而不提供标题,实际上,如果您尝试为GET请求调用GetRequestStream,它将抛出异常。
eeeeaaii

Answers:


10

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


我没有尝试过,这看起来是个不错的选择。谢谢!
eeeeaaii

1
出于某种原因对我不起作用,尽管无论如何这似乎是最好的答案(我不会取消选中标记)。请参阅我的文章在这里:stackoverflow.com/questions/3822941/...
eeeeaaii

嗯..当然,这一直对我有用-我一直在做控制台应用程序。您是否确定已授予ASP.NET标识(​​帐户)对要在其中写入跟踪输出的文件/目录的写访问权限?
feroze 2010年

对我来说效果很好-使用控制台应用程序。是一个拼写错误,导致其失败。谢谢!
编码员

114
这种答案应包括说明。
Demodave

148

我意识到这是一个古老的问题。@feroze的答案说明了要执行的操作,但没有详细介绍如何设置System.Net跟踪以实现此目标。

由于这个问题是我对该主题进行查询的第一个Google结果,并且由于我们都是忙碌的人,所以我认为我可以避免所有人都不必查找这些信息。

System.WebHttpWebRequests的调试非常强大,可以使用以下命令轻松设置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服务客户端错误的原因时,我发现这特别有用。原来我缺少标题。


5
哇。这个小工具正是我所需要的。我有一个控制台程序发出的后期请求运行正常,但一个ASP.NET WebForm应用程序却因相同的请求而失败。该实用程序向我展示了原始POST请求中的区别,这正是我所需要的!只需将其适当地添加到web.config和app.config文件中即可。谢谢kamui!
罗伯特·H·布尔多

3
这比烦恼设置/使用Fiddler或Wireshark方便得多。
Sabuncu

2
如果您愿意,可以使用一些时间戳记-有关详细信息,请参见以下答案和评论:stackoverflow.com/a/867328/1880663 简短的版本是,您应该在配置文件中添加以下内容: <add name="MyTraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="System.Net.trace.log" traceOutputOptions="DateTime" />
Adam Goodwin

5

您可以使用wireshark之类的网络流量嗅探器。

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


如果这就像我过去在家中安装的典型数据包嗅探器一样,则很可能需要我没有在这里工作的管理员访问权限级别。我将无法在办公室中使用它,因为简单地说,我将能够阅读老板的电子邮件。具有讽刺意味的是,如果我可以将桌面远程访问生产服务器,则可能更容易获得管理员访问权限,但是问题是我根本没有访问它们的权限,甚至没有推送文件的权限(另一家公司也这样做)。
eeeeaaii

1
我只会使用上面概述的技术-使用web.config文件在您的appdomain中安装一个Tracelistener,然后让tracelistener将调试消息写入本地磁盘或WebPate中,然后将WebPate呈现给客户端。
feroze

1
我发现Fiddler(fiddler2.com)是解决此问题的非常简单的方法。

请记住,Wireshark不会捕获localhost流量。而是使用一个名为RawCap的工具来捕获到文件的本地主机流量,然后使用Wireshark对其进行分析。
mfloryan 2014年

4

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

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

然后仅更改HttpWebRequest中的URL指向此新端点,但将请求的所有其他元素保持不变。将结果写到文件或其他东西上,您就很高兴。


3

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

这是一个简单的示例,说明如何使用该工具进行操作:

  1. 确保已启用捕获流量: 在此处输入图片说明
  2. 打开浏览器并刷新页面,或仅通过HTTP客户端发送请求。 在此处输入图片说明
  3. 切换到提琴手之后,您应该看到您的请求: 在此处输入图片说明
  4. 在顶部尝试浏览“原始”标签。 在此处输入图片说明
  5. 在下面的窗口中是您的原始请求 在此处输入图片说明

如果有密钥,是否可以查看HTTPS请求并对其进行解密?
Muflix

1
您能否检查一下:docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS或尝试使用google:“ telerik fiddler捕获https流量”。
Mroczny Arturek,

2

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

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

它的设计非常简单,只需将文件添加到项目中,然后调用:

System.Diagnostics.HttpRawTraceListener.Initialize();

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

对于每种情况,它可能都不是100%完美的(例如,它不是代理,因此它不会捕获来自浏览器的Web请求),但是它对于捕获HttpWebRequests对Web服务的请求/响应的效果很好。如果您需要这样的东西,可以作为一个很好的起点。


这正是我所需要的,但我无法使其正常运行。我在控制台应用程序中有静态main方法。我initialized() HttpRawTraceListener也进行了设置,FinishedCommunication但是当我执行HttpClient().PostAsync()任何操作时都没有发现:/我正在使用.net framework 4.6.1
Muflix

使用HttpClient.PostAsync将在响应上导致缓冲的读取/延迟结果,这将不属于System.Net日志记录,因此最终结果是侦听器类将无法按顺序查看完整的响应完成沟通。
jhilgeman

1
但是,我可能可以将侦听器更新为仅侦听该场景并完成通信,因此您可以看到除原始响应正文之外的所有内容。
jhilgeman

喜欢这个想法,并在很多地方看到它。但是,当我运行它时,它会通过初始化方法引发null ref异常。在.net 4.5框架上,内部system.net.logging类型可以正常加载,但找不到名为s_LoggingInitialized,s_LoggingEnabled或属性“ Web”的任何字段。
乔什

1

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

编辑:更新链接。


是的,我想过要这样做,这似乎是唯一的方法。但是它引入了很多复杂性。假设我实现了一个与站点位于同一服务器上的Web代理。它与输出有什么关系?记录到文件?鉴于我无权访问服务器,有没有办法连接到代理并查看日志?我认为很难或不可能在生产服务器上进行设置,因为这将需要打开一个新端口以将代理流量定向到该端口,而管理员则不允许这样做。
eeeeaaii

好了,代理可以拒绝所有不是来自本地计算机的请求。您无需向外界开放端口。您可以仅在#IF DEBUG部分中通过代理完成所有这些操作或仅执行请求。将其记录到事件日志或文件中,然后让生产将日志发送给您。除了要求他们在生产机器上为您运行Fiddler外,这就是您能做到的最好。就个人而言,老实说,如果这意味着节省时间和金钱,而不是认真使用自己的进程内代理记录器,我会争取(他们运行Fiddler)。
Mike Atlas 2010年

另外,您能否仅使用一些虚拟机来设置模拟您的生产环境的测试服务器?问题真的仅限于这台机器吗?
Mike Atlas 2010年

2
您不会相信维护这些服务器所涉及的官僚主义……我认为system.net跟踪可能是解决此问题的最佳方法。
eeeeaaii

0

您说自己以为.NET对您说谎,给出的具体示例是Content-LengthHTTP响应中缺少标头。

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


我说的是请求,而不是响应。这是我进行的测试:我运行了程序,它发出了http请求并得到了响应。然后,我根据.NET告诉我发送的确切信息(打印HttpWebRequest.Headers,HttpWebRequest.Method等),手工制作了一个请求(在提琴手中)。具体来说,此请求省略了Content-Length。但是服务器返回一个错误,指出需要Content-Length(这是合理的,因为它是POST请求)。因此,我很难信任.NET报告的内容。
eeeeaaii

ps也是如此,当我在具有两个不同版本的.NET的两个服务器上运行它时,完全相同的.NET代码报告了一组不同的标头。现在,也许.NET的两个版本实际上产生了不同的标头IDK。但这仍然使我感到怀疑,我想要一个原始的转储。
eeeeaaii

w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 -Content-Length不能用在许多情况下,采用分块传输编码时,包括给予。目标服务器是否支持HTTP / 1.1?
yfeldblum

很好,服务器已配置为在缺少Content-Length时返回411错误(通过在提琴手中手工制作请求进行测试)。因此,关键是,当我实例化HttpWebRequest并进行设置,然后打印出标题时,它不包含Content-Length作为标题。但是,如果这是真的,那么当我在httpWebRequest上调用GetResponse时,它将得到411-但这不是我得到的错误。它成功获得了200,并给了我不好的数据(一个不同的问题)。因此,.NET在头文件周围撒谎。
eeeeaaii
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.