Ich benutze das Spring RestTemplate schon eine Weile und stoße ständig gegen eine Wand, wenn ich versuche, die Anfragen und Antworten zu debuggen. Grundsätzlich möchte ich die gleichen Dinge sehen, die ich sehe, wenn ich Curl mit aktivierter Option "Ausführlich" verwende. Zum Beispiel :
curl -v http://twitter.com/statuses/public_timeline.rss
Zeigt sowohl die gesendeten als auch die empfangenen Daten an (einschließlich der Header, Cookies usw.).
Ich habe einige verwandte Beiträge überprüft wie: Wie protokolliere ich die Antwort in Spring RestTemplate? Aber ich habe es nicht geschafft, dieses Problem zu lösen.
Eine Möglichkeit, dies zu tun, wäre, den RestTemplate-Quellcode tatsächlich zu ändern und dort einige zusätzliche Protokollierungsanweisungen hinzuzufügen, aber ich würde diesen Ansatz wirklich als letzten Ausweg betrachten. Es sollte eine Möglichkeit geben, Spring Web Client / RestTemplate anzuweisen, alles viel freundlicher zu protokollieren.
Mein Ziel wäre es, dies mit Code wie folgt tun zu können:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
und dann, um die gleiche Art von Debug-Informationen (wie bei Curl) in der Protokolldatei oder in der Konsole abzurufen. Ich glaube, dies wäre äußerst nützlich für alle, die Spring RestTemplate verwenden und Probleme haben. Die Verwendung von Curl zum Debuggen Ihrer RestTemplate-Probleme funktioniert einfach nicht (in einigen Fällen).
quelle
Antworten:
Um das Beispiel mit einer vollständigen Implementierung zu vervollständigen
ClientHttpRequestInterceptor
, um Anforderung und Antwort zu verfolgen:Dann instanziieren Sie
RestTemplate
mit aBufferingClientHttpRequestFactory
undLoggingRequestInterceptor
:Dies
BufferingClientHttpRequestFactory
ist erforderlich, da wir den Antworttext sowohl im Interceptor als auch für den anfänglichen aufrufenden Code verwenden möchten. Die Standardimplementierung erlaubt es, den Antworttext nur einmal zu lesen.quelle
BufferingClientHttpResponseWrapper
wie @sofienezaghdoudi impliziert konfiguriert ist . Es funktioniert jedoch nicht, wenn es in Tests mit dem mockServer-Framework von spring verwendet wird, daMockRestServiceServer.createServer(restTemplate)
die RequestFactory auf überschrieben wirdInterceptingClientHttpRequestFactory
.In Spring Boot können Sie die vollständige Anforderung / Antwort erhalten, indem Sie dies in den Eigenschaften (oder einer anderen 12-Faktor-Methode) festlegen.
dies gibt aus
und Antwort
oder nur
logging.level.org.apache.http.wire=DEBUG
welche scheint alle relevanten Informationen zu enthaltenquelle
by default the RestTemplate relies on standard JDK facilities to establish HTTP connections. You can switch to use a different HTTP library such as Apache HttpComponents
http-outgoing-0 << "[0x1f][0x8b][0x8][0x0][0x0][0x0][0x0][0x0]
Erweitern Sie die Antwort von @hstoerr mit einem Code:
Erstellen Sie LoggingRequestInterceptor, um Anforderungsantworten zu protokollieren
Richten Sie RestTemplate ein
quelle
Am besten fügen Sie
logging.level.org.springframework.web.client.RestTemplate=DEBUG
derapplication.properties
Datei etwas hinzu.Andere Lösungen wie das Einstellen
log4j.logger.httpclient.wire
funktionieren nicht immer, da davon ausgegangen wird, dass Sielog4j
Apache verwendenHttpClient
, was nicht immer der Fall ist.Beachten Sie jedoch, dass diese Syntax nur bei den neuesten Versionen von Spring Boot funktioniert.
quelle
wire
Protokollierung, es enthält nur wichtige Informationen wie URL, Resepone-Code, POST-Parameter usw.Keine dieser Antworten löst tatsächlich 100% des Problems. mjj1409 bekommt das meiste davon, vermeidet jedoch bequemerweise das Problem der Protokollierung der Antwort, was etwas mehr Arbeit erfordert. Paul Sabou bietet eine Lösung, die realistisch erscheint, aber nicht genügend Details für die tatsächliche Implementierung bietet (und bei mir überhaupt nicht funktioniert hat). Sofiene hat die Protokollierung erhalten, aber mit einem kritischen Problem: Die Antwort ist nicht mehr lesbar, da der Eingabestream bereits verbraucht wurde!
Ich empfehle, einen BufferingClientHttpResponseWrapper zu verwenden, um das Antwortobjekt so zu verpacken, dass der Antworttext mehrmals gelesen werden kann:
Dadurch wird der InputStream nicht verbraucht, da der Antworttext in den Speicher geladen ist und mehrmals gelesen werden kann. Wenn Sie den BufferingClientHttpResponseWrapper nicht in Ihrem Klassenpfad haben, finden Sie die einfache Implementierung hier:
https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
So richten Sie das RestTemplate ein:
quelle
status==200
, bevorresponseCopy.getBody()
asyncRestTemplate
? Es würde erforderlich sein, a zurückzugeben,ListenableFuture
wenn Sie es abfangen, wasBufferingClientHttpResponseWrapper
in einem Rückruf nicht geändert werden kann.Die von Xenoterracid gegebene Lösung ist zu verwenden
ist gut, aber das Problem ist, dass standardmäßig Apache HttpComponents nicht verwendet wird.
Um Apache HttpComponents zu verwenden, fügen Sie Ihrer pom.xml hinzu
und konfigurieren
RestTemplate
mit:quelle
Sie können den Spring-Rest-Template-Logger verwenden , um den
RestTemplate
HTTP-Verkehr zu protokollieren .Fügen Sie Ihrem Maven-Projekt eine Abhängigkeit hinzu:
Passen Sie dann Ihre
RestTemplate
wie folgt an:Stellen Sie sicher, dass die Debug-Protokollierung aktiviert ist in
application.properties
:Jetzt wird der gesamte HTTP-Verkehr von RestTemplate
org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
auf Debug-Ebene protokolliert .HAFTUNGSAUSSCHLUSS: Ich habe diese Bibliothek geschrieben.
quelle
Ich habe endlich einen Weg gefunden, dies richtig zu machen. Der größte Teil der Lösung stammt von Wie konfiguriere ich Spring und SLF4J, damit ich die Protokollierung erhalten kann?
Es scheint, dass zwei Dinge getan werden müssen:
log4j.logger.httpclient.wire=DEBUG
Das zweite Problem tritt hauptsächlich in Frühlingsumgebungen auf, in denen slf4j verwendet wird (wie es mein Fall war). Stellen Sie daher bei Verwendung von slf4j sicher, dass die folgenden zwei Dinge geschehen:
In Ihrem Klassenpfad befindet sich keine Commons-Logging-Bibliothek. Dies kann durch Hinzufügen der Ausschlussdeskriptoren in Ihrem POM erfolgen:
Die Datei log4j.properties wird irgendwo im Klassenpfad gespeichert, wo Spring sie finden / sehen kann. Wenn Sie Probleme damit haben, besteht eine letzte Möglichkeit darin, die Datei log4j.properties in das Standardpaket aufzunehmen (keine gute Vorgehensweise, aber nur um sicherzustellen, dass die Dinge wie erwartet funktionieren).
quelle
httpclient.wire
stammt tatsächlich aus der Apache HttpComponents HttpClient-Bibliothek (siehe hc.apache.org/httpcomponents-client-ga/logging.html ). Diese Technik funktioniert nur, wenn Sie dieRestTemplate
Verwendung vonHttpComponentsClientHttpRequestFactory
RestTemplate protokollieren
Option 1. Öffnen Sie die Debug-Protokollierung.
Konfigurieren Sie RestTemplate
Standardmäßig stützt sich das RestTemplate auf Standard-JDK-Funktionen, um HTTP-Verbindungen herzustellen. Sie können wechseln, um eine andere HTTP-Bibliothek wie Apache HttpComponents zu verwenden
@Bean public RestTemplate restTemplate (Builder RestTemplateBuilder) {RestTemplate restTemplate = builder.build (); return restTemplate; }}
Konfigurieren Sie die Protokollierung
application.yml
Protokollierung: Ebene: org.springframework.web.client.RestTemplate: DEBUG
Option 2. Verwenden von Interceptor
Wrapper-Antwort
Implementieren Sie Interceptor
Konfigurieren Sie RestTemplate
Konfigurieren Sie die Protokollierung
Überprüfen Sie das Paket von LoggingRestTemplate, zum Beispiel in
application.yml
:logging: level: com.example.logging: DEBUG
Option 3. Verwenden von httpcomponent
Importieren Sie die httpcomponent-Abhängigkeit
Konfigurieren Sie RestTemplate
Konfigurieren Sie die Protokollierung
Überprüfen Sie das Paket von LoggingRestTemplate, zum Beispiel in
application.yml
:Protokollierung: Ebene: org.apache.http: DEBUG
quelle
TestRestTemplate
konfigurierenRestTemplateBuilder
möchten , konfigurieren Sie : @Bean public RestTemplateBuilder restTemplateBuilder () {neuen RestTemplateBuilder () zurückgeben. AdditionalInterceptors (Collections.singletonList (new LoggingRestTemplate ())); }---- Juli 2019 ----
(mit Spring Boot)
Ich war überrascht, dass Spring Boot mit all seiner Magie der Nullkonfiguration keine einfache Möglichkeit bietet, einen einfachen JSON-Antworttext mit RestTemplate zu überprüfen oder zu protokollieren. Ich habe die verschiedenen Antworten und Kommentare hier durchgesehen und teile meine eigene destillierte Version dessen, was (noch) funktioniert, und scheint mir angesichts der aktuellen Optionen eine vernünftige Lösung zu sein (ich verwende Spring Boot 2.1.6 mit Gradle 4.4 )
1. Verwenden von Fiddler als http-Proxy
Dies ist eigentlich eine ziemlich elegante Lösung, da sie alle mühsamen Anstrengungen umgeht, einen eigenen Interceptor zu erstellen oder den zugrunde liegenden http-Client in Apache zu ändern (siehe unten).
und dann
2. Verwenden von Apache HttpClient
Fügen Sie Apache HttpClient zu Ihren Maven- oder Gradle-Abhängigkeiten hinzu.
Verwendung
HttpComponentsClientHttpRequestFactory
als RequestFactory für RestTemplate. Der einfachste Weg, dies zu tun, wäre:Aktivieren Sie DEBUG in Ihrer
application.properties
Datei (wenn Sie Spring Boot verwenden).Wenn Sie Spring Boot verwenden, müssen Sie sicherstellen, dass ein Protokollierungsframework eingerichtet ist, z. B. mithilfe einer Spring-Boot-Starter-Abhängigkeit, die Folgendes enthält
spring-boot-starter-logging
.3. Verwenden Sie einen Interceptor
Ich lasse Sie die Vorschläge, Gegenvorschläge und Fallstricke in den anderen Antworten und Kommentaren durchlesen und selbst entscheiden, ob Sie diesen Weg gehen möchten.
4. Protokollieren Sie die URL und den Antwortstatus ohne Text
Obwohl dies nicht den angegebenen Anforderungen für die Protokollierung des Körpers entspricht, können Sie schnell und einfach mit der Protokollierung Ihrer REST-Aufrufe beginnen. Es zeigt die vollständige URL und den Antwortstatus an.
Fügen Sie einfach die folgende Zeile zu Ihrer
application.properties
Datei hinzu (vorausgesetzt, Sie verwenden Spring Boot und verwenden eine Spring Boot-Starter-Abhängigkeit, die Folgendes enthältspring-boot-starter-logging
).Die Ausgabe sieht ungefähr so aus:
quelle
Neben der in der anderen Antwort beschriebenen HttpClient-Protokollierung können Sie auch einen ClientHttpRequestInterceptor einführen, der den Hauptteil der Anforderung und die Antwort liest und protokolliert. Möglicherweise möchten Sie dies tun, wenn andere Inhalte auch den HttpClient verwenden oder wenn Sie ein benutzerdefiniertes Protokollierungsformat wünschen. Achtung: Sie sollten dem RestTemplate eine BufferingClientHttpRequestFactory geben, damit Sie die Antwort zweimal lesen können.
quelle
Wie in den anderen Antworten angegeben, muss der Antwortkörper speziell behandelt werden, damit er wiederholt gelesen werden kann (standardmäßig wird sein Inhalt beim ersten Lesen verbraucht).
Anstatt das
BufferingClientHttpRequestFactory
beim Einrichten der Anforderung zu verwenden, kann der Interceptor selbst die Antwort umbrechen und sicherstellen, dass der Inhalt beibehalten und wiederholt gelesen werden kann (sowohl vom Logger als auch vom Verbraucher der Antwort):Mein Abfangjäger, der
Code:
Aufbau:
Beispiel für eine Protokollausgabe:
quelle
application.properties
application.yml
quelle
Dies ist möglicherweise nicht der richtige Weg, aber ich denke, dies ist der einfachste Ansatz, um Anfragen und Antworten zu drucken, ohne zu viele Protokolle auszufüllen.
Durch Hinzufügen von 2 Zeilen protokolliert application.properties alle Anforderungen und Antworten in der ersten Zeile, um die Anforderungen zu protokollieren, und in der zweiten Zeile, um die Antworten zu protokollieren.
quelle
Angenommen
RestTemplate
wird konfiguriert Httpclient 4.x zu verwenden, können Sie bis auf Httpclient die Protokollierung Dokumentation lesen hier . Die Logger unterscheiden sich von den in den anderen Antworten angegebenen.Die Protokollierungskonfiguration für HttpClient 3.x finden Sie hier .
quelle
So viele Antworten hier erfordern Codierungsänderungen und angepasste Klassen und es ist wirklich nicht notwendig. Holen Sie sich einen Debugging-Proxy wie Fiddler und stellen Sie Ihre Java-Umgebung so ein, dass der Proxy in der Befehlszeile (-Dhttp.proxyHost und -Dhttp.proxyPort) verwendet wird. Führen Sie dann Fiddler aus, und Sie können die Anforderungen und Antworten in ihrer Gesamtheit sehen. Darüber hinaus bietet es viele zusätzliche Vorteile, z. B. die Möglichkeit, die Ergebnisse und Antworten vor und nach dem Senden an Experimente zu basteln, bevor Änderungen am Server vorgenommen werden.
Das letzte Problem, das auftreten kann, ist, dass Sie, wenn Sie HTTPS verwenden müssen, das SSL-Zertifikat von Fiddler exportieren und in den Java-Keystore (Cacerts) importieren müssen. Hinweis: Das Standardkennwort für den Java-Keystore lautet normalerweise "changeit".
quelle
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888
.Für die Protokollierung bei Logback mit Hilfe von Apache HttpClient:
Sie benötigen Apache HttpClient im Klassenpfad:
Konfigurieren Sie Ihren
RestTemplate
für die Verwendung von HttpClient:Fügen Sie der Protokollierungskonfigurationsdatei Folgendes hinzu, um Anforderungen und Antworten zu protokollieren:
Oder um noch mehr zu protokollieren:
quelle
org.apache.http.wire=DEBUG
in Ihremapplication.properties
JetztDer Trick, Ihr
RestTemplate
mit einem zu konfigurieren,BufferingClientHttpRequestFactory
funktioniert nicht, wenn Sie eines verwendenClientHttpRequestInterceptor
, was Sie tun werden, wenn Sie versuchen, sich über Interceptors anzumelden. Dies liegt an der Art und Weise, wieInterceptingHttpAccessor
(welcheRestTemplate
Unterklasse).Lange
RestTemplate
Rede, kurzer Sinn ... verwenden Sie einfach diese Klasse anstelle von (beachten Sie, dass hierfür die SLF4J-Protokollierungs-API verwendet wird, bearbeiten Sie sie nach Bedarf):Ich stimme zu, es ist albern, dass es so viel Arbeit kostet, dies zu tun.
quelle
In der obigen Diskussion werden nur Happy-Szenarien dargestellt. Wahrscheinlich können Sie die Antwort nicht protokollieren, wenn ein Fehler auftritt.
In diesem Fall und in allen oben genannten Fällen müssen Sie DefaultResponseErrorHandler überschreiben und wie folgt festlegen
quelle
Seltsamerweise funktioniert keine dieser Lösungen, da RestTemplate bei einigen Client- und Server-500x-Fehlern anscheinend keine Antwort zurückgibt. In diesem Fall müssen Sie diese ebenfalls protokollieren, indem Sie ResponseErrorHandler wie folgt implementieren. Hier ist ein Codeentwurf, aber Sie verstehen:
Sie können denselben Interceptor wie den Fehlerbehandler festlegen:
Und der Intercept implementiert beide Schnittstellen:
quelle
Wie @MilacH hervorhob, liegt ein Fehler in der Implementierung vor. Wenn ein statusCode> 400 zurückgegeben wird, wird eine IOException von Interceptors ausgelöst, da der errorHandler nicht aufgerufen wird. Die Ausnahme kann ignoriert werden und wird dann in der Handler-Methode erneut abgefangen.
quelle
Beste Lösung jetzt, fügen Sie einfach Abhängigkeit hinzu:
Es enthält eine LoggingRequestInterceptor-Klasse, die Sie auf diese Weise zu Ihrer RestTemplate hinzufügen können:
Integrieren Sie dieses Dienstprogramm, indem Sie es wie folgt als Interceptor zu einem Spring RestTemplate hinzufügen:
und fügen Sie Ihrem Framework eine slf4j-Implementierung wie log4j hinzu.
oder verwenden Sie direkt "Zg2proRestTemplate" . Die "beste Antwort" von @PaulSabou sieht so aus, da httpclient und alle apache.http-Bibliotheken bei Verwendung einer Spring RestTemplate nicht unbedingt geladen werden.
quelle
log("Headers: {}", request.headers)
InLoggingRequestInterceptor:traceRequest
undlog("Headers: {}", response.headers)
InLoggingRequestInterceptor:logResponse
. Möglicherweise möchten Sie einige Flags zum Protokollieren von Headern und Text hinzufügen. Außerdem möchten Sie möglicherweise den Inhaltstyp des Körpers für die Protokollierung überprüfen (z. B. nur Anwendung / json * protokollieren). Dies sollte auch konfigurierbar sein. Alles in allem haben Sie mit diesen kleinen Verbesserungen eine schöne Bibliothek zum Verbreiten. gute Arbeit :)Wollte auch meine Implementierung hinzufügen. Ich entschuldige mich für all die fehlenden Semikolons, dies ist in Groovy geschrieben.
Ich brauchte etwas Konfigurierbareres als die akzeptierte Antwort. Hier ist eine Rest Template Bean, die sehr agil ist und alles protokolliert, was das OP sucht.
Benutzerdefinierte Protokollierungs-Interceptor-Klasse:
Rest Template Bean Definition:
Implementierung:
quelle
Informationen zum Protokollieren der Anforderung und Antwort für die Restvorlage finden Sie in den Fragen und Antworten, indem Sie die mehrfachen Lesevorgänge im HttpInputStream aktivieren
Warum mein benutzerdefinierter ClientHttpRequestInterceptor mit leerer Antwort
quelle
org.apache.http.wire gibt zu unlesbare Protokolle, daher verwende ich das Logbuch , um das Anwendungsservlet und RestTemplate zu protokollieren
build.gradle
application.properties
RestTemplate
quelle
Im Zusammenhang mit der Antwort mit ClientHttpInterceptor habe ich einen Weg gefunden, die gesamte Antwort ohne Pufferfabriken beizubehalten. Speichern Sie einfach den Eingabestream des Antworttextes im Byte-Array mit einer Utils-Methode, die dieses Array aus dem Text kopiert. Wichtig ist jedoch, dass Sie diese Methode mit try catch umgeben, da sie unterbrochen wird, wenn die Antwort leer ist (dies ist die Ursache für die Ausnahme des Ressourcenzugriffs) und Erstellen Sie in catch einfach ein leeres Byte-Array und anschließend eine anonyme innere Klasse von ClientHttpResponse mit diesem Array und anderen Parametern aus der ursprünglichen Antwort. Anschließend können Sie das neue ClientHttpResponse-Objekt an die Ausführungskette der Restvorlage zurückgeben und die Antwort mithilfe des zuvor gespeicherten Body-Byte-Arrays protokollieren. Auf diese Weise vermeiden Sie, dass InputStream in der eigentlichen Antwort verwendet wird, und Sie können die Antwort "Rest Template" unverändert verwenden. Hinweis,
quelle
Meine Logger-Konfiguration hat XML verwendet
dann bekommst du so etwas wie unten:
über HttpMessageConverterExtractor.java:92 müssen Sie weiterhin debuggen, und in meinem Fall habe ich Folgendes erhalten:
und das:
outputMessage.getBody () enthält die Nachricht, die http (Post-Typ) sendet
quelle