Wie sehe ich die rohe HTTP-Anforderung, die die HttpWebRequest-Klasse sendet?

70

Ich weiß, dass Sie alle antworten werden "Verwenden Sie einen Debugging-Proxy-Server wie Fiddler", aber es ist nicht so einfach.

Hier ist meine Situation: Ich habe Code, der auf einem Server in einer ASP.NET-Seite Code-Behind (aspx.cs) ausgeführt wird, der (unter anderem) eine Verbindung zu einem anderen Server herstellt, einige Dinge abruft und diese dann formatiert und gibt es an den Browser zurück.

Das Problem ist, dass der andere Server das Falsche tut und ich daher in der Lage sein möchte, ein Debugging-Flag an die Seite zu übergeben (über die Abfragezeichenfolge, z. B.? Debug = true), damit das vollständig rohe HTTP ausgedruckt wird Bitten Sie darum, dass es an den anderen Server gesendet wird, damit ich sehen kann, was zum Teufel falsch ist. Dieser Code wird an mehreren Stellen ausgeführt, daher möchte ich dieses Flag nur für Entwickler, Staging oder Produktion übergeben und nur die Anforderung anzeigen können, ohne herausfinden zu müssen, ob die Produktionsserver mit einem irgendwo vorhandenen Proxyserver kommunizieren können , usw.

Sie würden denken, dass es einfach wäre, dies zu tun, oder? Ich fühle mich also verrückt oder so, aber ich habe mir die Referenz für HttpWebRequest und die übergeordnete Klasse WebRequest angesehen und - nichts. Geht nicht. Sie würden denken, Microsoft hätte daran gedacht. Das Nächste ist, dass Sie auf die "Headers" -Sammlung zugreifen können, aber als ich es ausprobiert habe, wurden einige wirklich wichtige Header wie "content length" weggelassen - also muss es mich "anlügen" (ich weiß, dass es lügt, weil ich es weiß für die Tatsache, dass der Remote-Server einen 200-Status zurückgibt - die Anforderung ist erfolgreich, es werden nur schlechte / andere / falsche Daten zurückgegeben)

Hier ist das angeforderte Codebeispiel:

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();
eeeeaaii
quelle
1
Können Sie HttpWebRequest durch eine andere Komponente ersetzen? Wenn ja, können Sie eine HTTP-Komponente eines Drittanbieters verwenden, mit der Sie alles erfassen können, was gesendet wird (oder die Header), um den Job auszuführen.
Eugene Mayevski 'Rückruf
Haben Sie Firebug für Firefox ausprobiert? Es ist ziemlich mächtig, ich weiß nicht, wie es mit Fiddler verglichen wird, aber vielleicht hat es das, was Sie brauchen?
Grahame A
8
Firebug hilft nicht weiter, da der interessante Teil zwischen zwei Servern stattfindet - Firebug befindet sich in Firefox und kann nur überprüfen, was zwischen einem Server und dem Client geschieht.
tdammers
Eugene, kennst du irgendwelche Komponenten? Ich habe darüber nachgedacht, meine eigene Version von HttpWebRequest zu implementieren, aber das ist eine Menge Arbeit. Ich weiß nicht, ob es möglich ist, HttpWebRequest zu unterordnen und auf diese Weise auf nützliche Eigenschaften zuzugreifen.
Eeeeaaii
2
Jim, ich habe ein Codebeispiel hinzugefügt. In meinem Fall handelt es sich um einen POST, und ich rufe GetRequestStream auf, möchte dies jedoch für jede Art von Anforderung, GET oder POST, tun können. Beachten Sie, dass GetRequestStream nur den Inhalt / Text enthält, nicht die Header. Tatsächlich wird eine Ausnahme ausgelöst, wenn Sie versuchen, GetRequestStream für eine GET-Anforderung aufzurufen.
Eeeeaaii

Antworten:

10

Sie können den System.Net-Ablaufverfolgungsmechanismus verwenden, um die auf der Leitung gesendeten HTTP-Rohanforderungen anzuzeigen. Sie können dem Prozess auch Ihren eigenen Tracelistener hinzufügen.

Feroze
quelle
Ich habe das nicht ausprobiert, das scheint eine gute Option zu sein. Vielen Dank!
Eeeeaaii
1
hat aus irgendeinem Grund nicht für mich funktioniert, obwohl dies sowieso die beste Antwort zu sein scheint (ich werde das Häkchen nicht entfernen). Siehe meinen Beitrag hier: stackoverflow.com/questions/3822941/…
eeeeaaii
Hmm .. Das hat natürlich immer bei mir funktioniert - ich mache immer Konsolen-Apps. Stellen Sie sicher, dass Sie der ASP.NET-Identität (Konto) Schreibzugriff auf die Datei / das Verzeichnis gewährt haben, in die bzw. das die Trace-Ausgabe geschrieben werden soll?
Feroze
Hat bei mir gut funktioniert - mit einer Konsolen-App. War ein Rechtschreibfehler, der dazu führte, dass es fehlschlug. Vielen Dank!
Der Codierer
114
Diese Art der Antwort sollte Anweisungen enthalten.
Demodave
148

Mir ist klar, dass dies eine alte Frage ist. Die Antwort von @ feroze sagt aus, was zu tun ist, geht jedoch nicht ins Detail, wie die System.NetAblaufverfolgung eingerichtet werden soll , um dies zu erreichen.

Da diese Frage das erste Google-Ergebnis für meine Anfrage zum Thema war und wir alle beschäftigt sind, dachte ich, ich würde Sie alle davor bewahren, diese Informationen suchen zu müssen.

System.Web ist sehr leistungsfähig zum Debuggen HttpWebRequest s und kann einfach eingerichtet werden mit 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>

Wenn Sie einen einfachen HttpWebRequestCode hinzufügen und im Debugging-Modus in Visual Studio ausgeführt werden, werden die folgenden Informationen in der Debug-Konsole angezeigt:

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

Ich fand dies besonders nützlich, wenn ich versuchte, die Ursache eines Webservice-Client-Fehlers herauszufinden. Es stellte sich heraus, dass mir ein Header fehlte.

Kamui
quelle
5
Beeindruckend. Dieses kleine Dienstprogramm war genau das, was ich brauchte. Ich hatte ein Konsolenprogramm, das Post-Anfragen stellte, das perfekt funktionierte, aber eine ASP.NET WebForm-Anwendung, die mit denselben Anfragen fehlschlug. Dieses Dienstprogramm hat mir den Unterschied in der rohen POST-Anfrage gezeigt, den ich brauchte! Fügen Sie es einfach den entsprechenden Dateien web.config und app.config hinzu. Danke Kamui!
Robert H. Bourdeau
3
So viel bequemer, als sich mit dem Einrichten / Verwenden von Fiddler oder Wireshark beschäftigen zu müssen.
Sabuncu
2
Wenn Sie dies möchten, ist es wahrscheinlich hilfreich, einige Zeitstempel zu haben. Weitere Informationen finden Sie in dieser Antwort und in den Kommentaren: stackoverflow.com/a/867328/1880663 In der Kurzversion sollten Sie Ihrer Konfigurationsdatei Folgendes hinzufügen: <add name="MyTraceFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="System.Net.trace.log" traceOutputOptions="DateTime" />
Adam Goodwin
5

Sie können einen Netzwerkverkehrs-Sniffer wie Wireshark verwenden .

Dies ist kein Debugging-Proxy, sondern überwacht den gesamten Datenverkehr und lässt Sie die unformatierten Anforderungen / Antworten sehen.

Oded
quelle
Wenn dies wie typische Paket-Sniffer ist, die ich in der Vergangenheit zu Hause installiert habe, würde dies höchstwahrscheinlich einen Administratorzugriff erfordern, den ich hier bei der Arbeit nicht habe. Ich würde es hier im Büro nicht verwenden können, weil ich, um es einfach auszudrücken, die E-Mails meiner Chefs lesen könnte. Ironischerweise könnte es einfacher sein, Administratorzugriff zu erhalten, wenn ich Remotedesktop auf die Produktionsserver übertragen könnte, aber das Problem dabei ist, dass ich überhaupt keinen Zugriff darauf habe, nicht einmal, um Dateien zu pushen (ein anderes Unternehmen tut das).
Eeeeaaii
1
Ich würde nur die oben beschriebene Technik verwenden - einen Tracelistener in Ihrer Appdomain mithilfe einer web.config-Datei installieren und den Tracelistener den Debug-Spew auf die lokale Festplatte oder in die Webpate schreiben lassen, die dann auf dem Client gerendert wird.
Feroze
1
Ich habe festgestellt, dass Fiddler ( fiddler2.com ) eine sehr einfache Lösung für dieses Problem ist.
Denken Sie daran, dass Wireshark keinen localhostDatenverkehr erfasst . Verwenden Sie stattdessen ein Tool namens RawCap , um den lokalen Host- Verkehr in einer Datei zu erfassen und ihn dann mit Wireshark zu analysieren.
Mfloryan
4

Ich beantworte hier meine eigene Frage, weil ich mir einen anderen Weg überlegt habe. Grundsätzlich besteht die Idee darin, dass Sie die HttpWebRequest erneut auf eine Seite verweisen, auf der die eingehende HTTP-Rohanforderung protokolliert wird. Mit anderen Worten, richten Sie einen benutzerdefinierten HTTP-Handler gemäß diesem Forumsbeitrag ein:

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

Ändern Sie dann nur die URL in der HttpWebRequest, um auf diesen neuen Endpunkt zu verweisen. Behalten Sie jedoch alle anderen Elemente der Anforderung bei. Schreiben Sie das Ergebnis in eine Datei oder etwas und Sie sind golden.

eeeeaaii
quelle
3

Ich empfehle Ihnen, Telerik Fiddler herunterzuladen , um eingehenden / ausgehenden Verkehr zu erfassen.

Hier ist ein einfaches Beispiel, wie es mit diesem Tool gemacht wird:

  1. Stellen Sie sicher, dass der Capture-Verkehr aktiviert ist: Geben Sie hier die Bildbeschreibung ein
  2. Öffnen Sie den Browser und aktualisieren Sie die Seite oder senden Sie einfach eine Anfrage über den HTTP-Client. Geben Sie hier die Bildbeschreibung ein
  3. Nach diesem Wechsel zum Fiddler sollten Sie Ihre Anfrage sehen: Geben Sie hier die Bildbeschreibung ein
  4. Versuchen Sie oben, auf der Registerkarte "Raw" zu navigieren. Geben Sie hier die Bildbeschreibung ein
  5. Im folgenden Fenster befindet sich Ihre Rohanforderung Geben Sie hier die Bildbeschreibung ein
Mroczny Arturek
quelle
Ist es möglich, HTTPS-Anforderungen anzuzeigen und zu entschlüsseln, wenn Sie den Schlüssel haben?
Muflix
1
Könnten Sie es überprüfen: docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS oder versuchen Sie es mit Google: "Telerik Fiddler Capture https Traffic".
Mroczny Arturek
2

Ich weiß, dass dies eine alte Frage ist, aber ich befand mich in einer schwierigen Situation, in der ich die Anwendungskonfigurationsdatei nicht kontrollierte. Daher brauchte ich eine einfache Möglichkeit, die Ablaufverfolgung über Code zu aktivieren und dann problemlos auf die unformatierten Anforderungs- / Antwortdaten in einem zuzugreifen Veranstaltung. Also habe ich diese benutzerdefinierte Klasse, HttpRawTraceListener, zusammengestellt, die für andere in meiner Position von Nutzen sein könnte:

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

Es wurde so einfach gestaltet, dass Sie die Datei zu Ihrem Projekt hinzufügen und dann Folgendes aufrufen:

System.Diagnostics.HttpRawTraceListener.Initialize();

... um die Ablaufverfolgung zu starten. Von dort werden Anforderungen / Antworten aus den Ablaufverfolgungsnachrichten analysiert und dann über das System.Diagnostics.HttpRawTraceListener.FinishedCommunication- Ereignis verfügbar gemacht .

Es ist wahrscheinlich nicht zu 100% perfekt für jedes Szenario (z. B. kein Proxy, sodass beispielsweise keine Webanforderungen von einem Browser erfasst werden), aber es funktioniert ziemlich gut zum Erfassen von HttpWebRequests-Anforderungen / -Antworten auf Webdienste Seien Sie ein guter Ausgangspunkt, wenn Sie so etwas brauchen.

jhilgeman
quelle
Das ist genau das, was ich brauche, aber ich kann es nicht zum Laufen bringen. Ich habe statische Hauptmethode in der Konsolenanwendung. Ich initialized() HttpRawTraceListenerund auch Setup, FinishedCommunicationaber wenn ich ausführe, wird HttpClient().PostAsync()nichts abgefangen: / Ich verwende .net Framework 4.6.1
Muflix
Die Verwendung von HttpClient.PostAsync führt zu einem gepufferten Lese- / Verzögerungsergebnis für die Antwort, das nicht Teil der System.Net-Protokollierung ist. Das Endergebnis ist also, dass die Listener-Klasse die vollständige Antwort nicht in der richtigen Reihenfolge sehen kann um die Kommunikation zu beenden.
jhilgeman
1
Allerdings könnte ich den Listener wahrscheinlich aktualisieren, um nur auf dieses Szenario zu warten und die Kommunikation trotzdem zu beenden, sodass Sie alles außer dem rohen Antworttext sehen können.
jhilgeman
liebte diese Idee und sah sie an zahlreichen Stellen erwähnt. Wenn ich dies jedoch ausführe, werden durch die Initialisierungsmethode null ref-Ausnahmen ausgelöst. Unter .net 4.5-Framework wird der interne system.net.logging-Typ in Ordnung geladen, es werden jedoch keine Felder mit den Namen s_LoggingInitialized, s_LoggingEnabled oder die Eigenschaft 'Web' gefunden.
Josh
1

Ein weiterer Vorschlag. Implementieren Sie Ihren eigenen Webproxy und legen Sie Ihre Anforderung für die Verwendung mit WebRequest.Proxy fest . Dann sollten Sie in der Lage sein, den Datenverkehr aus der Proxy-Instanz zu extrahieren.

Bearbeiten: Update für Links.

Mike Atlas
quelle
Ja, ich habe darüber nachgedacht, es scheint vielleicht der einzige Weg zu sein. Aber es bringt viel Komplexität mit sich. Angenommen, ich implementiere einen Webproxy, der sich auf demselben Server wie die Site befindet. Was macht es mit der Ausgabe? In eine Datei einloggen? Gibt es eine Möglichkeit, eine Verbindung zum Proxy herzustellen und das Protokoll anzuzeigen, da ich keinen Zugriff auf den Server habe? Ich denke, es wäre schwierig oder unmöglich, dies auf dem Produktionsserver einzurichten, da dafür ein neuer Port geöffnet werden müsste, auf den der Proxy-Verkehr geleitet werden kann, und dies würde von Administratoren nicht zugelassen.
Eeeeaaii
Nun, der Proxy könnte alle Anfragen ablehnen, die nicht vom lokalen Computer stammen. Sie müssen den Hafen nicht nach außen öffnen. Sie können all dies oder nur die Anforderungen über den Proxy nur in einem Abschnitt #IF DEBUG ausführen. Lassen Sie es im Ereignisprotokoll oder in einer Datei protokollieren und von der Produktion die Protokolle senden. Das ist ungefähr das Beste, was Sie tun können, außer sie zu bitten, Fiddler auf der Produktionsmaschine für Sie auszuführen. Persönlich würde ich ehrlich gesagt darauf drängen (sie führen Fiddler aus), wenn dies bedeutet, Zeit und Geld zu sparen, anstatt Ihren eigenen In-Process-Proxy-Logger ernsthaft zu rollen.
Mike Atlas
Können Sie auch nur Testserver einrichten, die Ihre Produktionsumgebung mit einigen VMs nachahmen? Ist das Problem wirklich nur auf diese eine Maschine beschränkt?
Mike Atlas
2
Sie würden nicht glauben, wie viel Bürokratie mit der Wartung dieser Server verbunden ist ... Ich denke, die System.net-Ablaufverfolgung könnte der beste Weg sein, dies zu tun.
Eeeeaaii
0

Sie sagen, dass Sie glauben, dass .NET Sie anlügt, und das konkrete Beispiel, das Sie geben, ist, dass der Header Content-Lengthin der HTTP-Antwort fehlt.

Der Header Content-Lengthwird jedoch nicht für eine HTTP-Antwort benötigt. Wenn sich der Hauptteil der Antwort in einer Dynamik befindet und seine Länge nicht im Voraus bekannt ist, ist es sehr wahrscheinlich, dass der Content-LengthHeader weggelassen wird!

Yfeldblum
quelle
Ich spreche von Anfragen, nicht von Antworten. Hier ist der Test, den ich durchgeführt habe: Ich habe das Programm ausgeführt, eine http-Anfrage gestellt und eine Antwort erhalten. Ich habe dann eine Anfrage (in Fiddler) handgefertigt, basierend auf den genauen Informationen, die .NET mir mitgeteilt hat (Drucken von HttpWebRequest.Headers, HttpWebRequest.Method usw.). Insbesondere wurde bei dieser Anforderung die Inhaltslänge weggelassen. Der Server kam jedoch mit einem Fehler zurück, der besagte, dass Inhaltslänge erforderlich war (was sinnvoll ist, da es sich um eine POST-Anforderung handelte). Daher habe ich Probleme, den .NET-Berichten zu vertrauen.
Eeeeaaii
ps Außerdem hat genau derselbe .NET-Code unterschiedliche Header gemeldet, als ich ihn auf zwei Servern mit zwei verschiedenen .NET-Versionen ausgeführt habe. Vielleicht produzierten die beiden Versionen von .NET tatsächlich unterschiedliche Header, IDK. Aber es macht mich trotzdem misstrauisch und ich hätte gerne eine rohe Müllkippe.
Eeeeaaii
w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 - Content-Lengthdarf unter bestimmten Umständen NICHT angegeben werden, auch nicht bei Verwendung der Chunked-Transfer-Codierung. Ist der Zielserver HTTP / 1.1-fähig?
Yfeldblum
Nun, der Server wurde so konfiguriert, dass er einen 411-Fehler zurückgibt, wenn Content-Length fehlt (dies wurde durch manuelles Erstellen einer Anfrage in Fiddler getestet). Der Punkt ist also, wenn ich eine HttpWebRequest instanziiere und einrichte und dann die Header drucke, enthält sie Content-Length nicht als Header. Aber wenn das wahr wäre, würde es einen 411 bekommen, wenn ich GetResponse auf httpWebRequest aufrufe - aber das ist nicht der Fehler, den ich bekomme. Es gelingt mit einer 200 und gibt mir schlechte Daten (ein anderes Problem). Deshalb lügt .NET über die Header.
Eeeeaaii