J'utilise Spring RestTemplate depuis un certain temps et je frappe constamment un mur lorsque j'essaie de déboguer ses demandes et réponses. Je cherche essentiellement à voir les mêmes choses que je vois lorsque j'utilise curl avec l'option "verbose" activée. Par exemple :
curl -v http://twitter.com/statuses/public_timeline.rss
Afficherait à la fois les données envoyées et les données reçues (y compris les en-têtes, les cookies, etc.).
J'ai vérifié certains articles connexes tels que: comment enregistrer la réponse dans Spring RestTemplate? mais je n'ai pas réussi à résoudre ce problème.
Une façon de le faire serait de changer le code source de RestTemplate et d'y ajouter des instructions de journalisation supplémentaires, mais je trouverais cette approche vraiment une solution de dernier recours. Il devrait y avoir un moyen de dire à Spring Web Client / RestTemplate de tout enregistrer de manière beaucoup plus conviviale.
Mon objectif serait de pouvoir le faire avec du code comme:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
puis pour obtenir le même type d'informations de débogage (que j'obtiens avec curl) dans le fichier journal ou dans la console. Je pense que cela serait extrêmement utile pour quiconque utilise le Spring RestTemplate et a des problèmes. L'utilisation de curl pour déboguer vos problèmes RestTemplate ne fonctionne tout simplement pas (dans certains cas).
la source
Réponses:
Juste pour compléter l'exemple avec une implémentation complète de
ClientHttpRequestInterceptor
pour tracer la demande et la réponse:Instanciez ensuite en
RestTemplate
utilisant aBufferingClientHttpRequestFactory
et leLoggingRequestInterceptor
:Le
BufferingClientHttpRequestFactory
est requis car nous voulons utiliser le corps de réponse à la fois dans l'intercepteur et pour le code d'appel initial. L'implémentation par défaut permet de lire le corps de réponse une seule fois.la source
BufferingClientHttpResponseWrapper
comme @sofienezaghdoudi l'implique. Cependant, cela ne fonctionne pas lorsqu'il est utilisé dans des tests utilisant le framework mockServer de Spring, car ilMockRestServiceServer.createServer(restTemplate)
écrase RequestFactory dansInterceptingClientHttpRequestFactory
.dans Spring Boot, vous pouvez obtenir la demande / réponse complète en définissant cela dans les propriétés (ou une autre méthode à 12 facteurs)
cela produit
et réponse
ou
logging.level.org.apache.http.wire=DEBUG
qui semble contenir toutes les informations pertinentesla source
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]
Extension de la réponse @hstoerr avec du code:
Créer LoggingRequestInterceptor pour enregistrer les réponses aux demandes
Configurer RestTemplate
la source
Votre meilleur pari est d'ajouter
logging.level.org.springframework.web.client.RestTemplate=DEBUG
auapplication.properties
fichier.D'autres solutions comme la configuration
log4j.logger.httpclient.wire
ne fonctionneront pas toujours car elles supposent que vous utilisezlog4j
et ApacheHttpClient
, ce qui n'est pas toujours vrai.Notez cependant que cette syntaxe ne fonctionnera que sur les dernières versions de Spring Boot.
la source
wire
journalisation, elle ne comprend que des informations essentielles comme l'URL, le code resepone, les paramètres POST, etc.Aucune de ces réponses ne résout réellement 100% du problème. mjj1409 obtient l'essentiel, mais évite commodément le problème de la journalisation de la réponse, ce qui prend un peu plus de travail. Paul Sabou fournit une solution qui semble réaliste, mais ne fournit pas suffisamment de détails pour être réellement mise en œuvre (et cela n'a pas fonctionné du tout pour moi). Sofiene a obtenu la journalisation mais avec un problème critique: la réponse n'est plus lisible car le flux d'entrée a déjà été consommé!
Je recommande d'utiliser un BufferingClientHttpResponseWrapper pour encapsuler l'objet de réponse pour permettre la lecture du corps de réponse plusieurs fois:
Cela ne consommera pas InputStream car le corps de la réponse est chargé en mémoire et peut être lu plusieurs fois. Si vous n'avez pas le BufferingClientHttpResponseWrapper sur votre chemin de classe, vous pouvez trouver l'implémentation simple ici:
https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
Pour configurer le RestTemplate:
la source
status==200
avantresponseCopy.getBody()
asyncRestTemplate
? Il faudrait retourner unListenableFuture
lorsque vous l'interceptez, ce qui n'est pas possible de modifier avecBufferingClientHttpResponseWrapper
dans un rappel.Vous pouvez utiliser Spring-rest-template-logger pour enregistrer le
RestTemplate
trafic HTTP.Ajoutez une dépendance à votre projet Maven:
Personnalisez ensuite votre
RestTemplate
comme suit:Assurez-vous que la journalisation du débogage est activée dans
application.properties
:Désormais, tout le trafic HTTP RestTemplate sera enregistré
org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
au niveau du débogage.AVERTISSEMENT: j'ai écrit cette bibliothèque.
la source
La solution donnée par le xénoterracide à utiliser
est bon mais le problème est que par défaut Apache HttpComponents n'est pas utilisé.
Pour utiliser Apache HttpComponents, ajoutez à votre pom.xml
et configurer
RestTemplate
avec:la source
J'ai finalement trouvé un moyen de le faire de la bonne façon. La plupart de la solution provient de Comment configurer Spring et SLF4J pour pouvoir me connecter?
Il semble qu'il y ait deux choses à faire:
log4j.logger.httpclient.wire=DEBUG
Le deuxième problème se produit principalement dans les environnements de printemps où slf4j est utilisé (comme c'était mon cas). En tant que tel, lorsque slf4j est utilisé, assurez-vous que les deux choses suivantes se produisent:
Il n'y a pas de bibliothèque de journalisation des biens communs dans votre chemin de classe: cela peut être fait en ajoutant les descripteurs d'exclusion dans votre pom:
Le fichier log4j.properties est stocké quelque part dans le chemin de classe où le printemps peut le trouver / le voir. Si vous avez des problèmes avec cela, une solution de dernier recours serait de placer le fichier log4j.properties dans le package par défaut (ce n'est pas une bonne pratique mais juste pour voir que les choses fonctionnent comme prévu)
la source
httpclient.wire
provient en fait de la bibliothèque Apache HttpComponents HttpClient (voir hc.apache.org/httpcomponents-client-ga/logging.html ). Cette technique ne fonctionnera que si vous avezRestTemplate
configuré pour utiliser leHttpComponentsClientHttpRequestFactory
Journalisation de RestTemplate
Option 1. Ouvrez la journalisation du débogage.
Configurer RestTemplate
Par défaut, le RestTemplate s'appuie sur des fonctionnalités JDK standard pour établir des connexions HTTP. Vous pouvez basculer pour utiliser une autre bibliothèque HTTP telle que Apache HttpComponents
@Bean public RestTemplate restTemplate (constructeur RestTemplateBuilder) {RestTemplate restTemplate = builder.build (); return restTemplate; }
Configurer la journalisation
application.yml
journalisation: niveau: org.springframework.web.client.RestTemplate: DEBUG
Option 2. Utilisation d'Interceptor
Réponse de Wrapper
Implémenter Interceptor
Configurer RestTemplate
Configurer la journalisation
Vérifiez le package de LoggingRestTemplate, par exemple dans
application.yml
:journalisation: niveau: com.example.logging: DEBUG
Option 3. Utilisation de httpcomponent
Importer la dépendance httpcomponent
Configurer RestTemplate
Configurer la journalisation
Vérifiez le package de LoggingRestTemplate, par exemple dans
application.yml
:journalisation: niveau: org.apache.http: DEBUG
la source
TestRestTemplate
, configurezRestTemplateBuilder
: @Bean public RestTemplateBuilder restTemplateBuilder () {return new RestTemplateBuilder (). AdditionalInterceptors (Collections.singletonList (new LoggingRestTemplate ())); }---- juillet 2019 ----
(en utilisant Spring Boot)
J'ai été surpris que Spring Boot, avec toute sa magie de configuration zéro, ne fournisse pas un moyen facile d'inspecter ou de consigner un corps de réponse JSON simple avec RestTemplate. J'ai parcouru les différentes réponses et commentaires fournis ici, et partage ma propre version distillée de ce qui fonctionne (encore) et me semble être une solution raisonnable, compte tenu des options actuelles (j'utilise Spring Boot 2.1.6 avec Gradle 4.4 )
1. Utilisation de Fiddler comme proxy http
C'est en fait une solution assez élégante, car elle contourne tous les efforts fastidieux de création de votre propre intercepteur ou de modification du client http sous-jacent en apache (voir ci-dessous).
puis
2. Utilisation d'Apache HttpClient
Ajoutez Apache HttpClient à vos dépendances Maven ou Gradle.
À utiliser
HttpComponentsClientHttpRequestFactory
comme RequestFactory pour RestTemplate. La façon la plus simple de le faire serait:Activez DEBUG dans votre
application.properties
fichier (si vous utilisez Spring Boot)Si vous utilisez Spring Boot, vous devrez vous assurer que vous disposez d'un cadre de journalisation, par exemple en utilisant une dépendance Spring-Boot-Starter qui inclut
spring-boot-starter-logging
.3. Utilisez un intercepteur
Je vais vous laisser lire les propositions, contre-propositions et accrochages dans les autres réponses et commentaires et décider par vous-même si vous voulez aller dans cette direction.
4. Consigner l'URL et l'état de réponse sans corps
Bien que cela ne réponde pas aux exigences déclarées de journalisation du corps, c'est un moyen rapide et simple de commencer à journaliser vos appels REST. Il affiche l'URL complète et l'état de la réponse.
Ajoutez simplement la ligne suivante à votre
application.properties
fichier (en supposant que vous utilisez Spring Boot et en supposant que vous utilisez une dépendance de démarrage Spring Spring qui inclutspring-boot-starter-logging
)La sortie ressemblera à ceci:
la source
Outre la journalisation HttpClient décrite dans l'autre réponse , vous pouvez également introduire un ClientHttpRequestInterceptor qui lit le corps de la demande et de la réponse et l'enregistre. Vous souhaiterez peut-être le faire si d'autres éléments utilisent également HttpClient ou si vous souhaitez un format de journalisation personnalisé. Attention: vous souhaiterez donner au RestTemplate un BufferingClientHttpRequestFactory de sorte que vous puissiez lire la réponse deux fois.
la source
Comme indiqué dans les autres réponses, le corps de la réponse a besoin d'un traitement spécial pour pouvoir être lu à plusieurs reprises (par défaut, son contenu est consommé lors de la première lecture).
Au lieu d'utiliser le
BufferingClientHttpRequestFactory
lors de la configuration de la demande, l'intercepteur lui-même peut encapsuler la réponse et s'assurer que le contenu est conservé et peut être lu à plusieurs reprises (par l'enregistreur ainsi que par le consommateur de la réponse):Mon intercepteur, qui
Code:
Configuration:
Exemple de sortie de journal:
la source
application.properties
application.yml
la source
Ce n'est peut-être pas la bonne façon de procéder, mais je pense que c'est l'approche la plus simple pour imprimer les demandes et les réponses sans trop remplir de journaux.
En ajoutant ci-dessous 2 lignes, application.properties enregistre toutes les demandes et réponses en 1ère ligne afin d'enregistrer les demandes et en 2e ligne pour enregistrer les réponses.
la source
En supposant qu'il
RestTemplate
est configuré pour utiliser HttpClient 4.x, vous pouvez lire ici la documentation de journalisation de HttpClient . Les enregistreurs sont différents de ceux spécifiés dans les autres réponses.La configuration de journalisation pour HttpClient 3.x est disponible ici .
la source
De nombreuses réponses ici nécessitent des modifications de codage et des classes personnalisées et ce n'est vraiment pas nécessaire. Gte un proxy de débogage tel que fiddler et configurez votre environnement java pour utiliser le proxy sur la ligne de commande (-Dhttp.proxyHost et -Dhttp.proxyPort) puis exécutez fiddler et vous pouvez voir les demandes et les réponses dans leur intégralité. Il présente également de nombreux avantages auxiliaires tels que la possibilité de bricoler les résultats et les réponses avant et après leur envoi pour exécuter des expériences avant de s'engager dans la modification du serveur.
Le dernier problème qui peut survenir est que si vous devez utiliser HTTPS, vous devrez exporter le certificat SSL de fiddler et l'importer dans le magasin de clés java (cacerts): le mot de passe par défaut du magasin de java est généralement "changeit".
la source
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888
.Pour vous connecter à Logback avec l'aide d'Apache HttpClient:
Vous avez besoin d'Apache HttpClient dans classpath:
Configurez votre
RestTemplate
pour utiliser HttpClient:Pour enregistrer les demandes et les réponses, ajoutez au fichier de configuration Logback:
Ou pour vous connecter encore plus:
la source
org.apache.http.wire=DEBUG
votreapplication.properties
maintenantL'astuce de configuration de votre
RestTemplate
avec unBufferingClientHttpRequestFactory
ne fonctionne pas si vous en utilisez unClientHttpRequestInterceptor
, ce que vous ferez si vous essayez de vous connecter via des intercepteurs. Cela est dû à la façon dontInterceptingHttpAccessor
(quellesRestTemplate
sous-classes) fonctionnent.Pour faire court ... utilisez simplement cette classe à la place de
RestTemplate
(notez que cela utilise l'API de journalisation SLF4J, modifiez-la si nécessaire):Je suis d'accord que c'est idiot qu'il faut autant de travail juste pour le faire.
la source
Ajoutant à la discussion ci-dessus, cela ne représente que des scénarios heureux. vous ne pourrez probablement pas enregistrer la réponse si une erreur survient.
Dans ce cas, plus tous les cas ci-dessus, vous devez remplacer DefaultResponseErrorHandler et le définir comme ci-dessous
la source
Étrangement, aucune de ces solutions ne fonctionne car RestTemplate ne semble pas renvoyer la réponse à certaines erreurs 500x du client et du serveur. Dans ce cas, vous devrez également les enregistrer en implémentant ResponseErrorHandler comme suit. Voici un projet de code, mais vous obtenez le point:
Vous pouvez définir le même intercepteur que le gestionnaire d'erreurs:
Et l'interception implémente les deux interfaces:
la source
Comme l'a souligné @MilacH, il y a une erreur dans l'implémentation. Si un statusCode> 400 est renvoyé, une IOException est levée, car le gestionnaire d'erreur n'est pas appelé, à partir des intercepteurs. L'exception peut être ignorée et est ensuite interceptée à nouveau dans la méthode du gestionnaire.
la source
Meilleure solution maintenant, ajoutez simplement la dépendance:
Il contient une classe LoggingRequestInterceptor que vous pouvez ajouter de cette façon à votre RestTemplate:
intégrer cet utilitaire en l'ajoutant en tant qu'intercepteur à un RestTemplate à ressort, de la manière suivante:
et ajoutez une implémentation slf4j à votre framework comme log4j.
ou utilisez directement "Zg2proRestTemplate" . La "meilleure réponse" de @PaulSabou semble ainsi, car httpclient et toutes les bibliothèques apache.http ne sont pas nécessairement chargées lors de l'utilisation d'un Spring RestTemplate.
la source
log("Headers: {}", request.headers)
inLoggingRequestInterceptor:traceRequest
andlog("Headers: {}", response.headers)
inLoggingRequestInterceptor:logResponse
. Vous voudrez peut-être penser à ajouter des indicateurs pour la journalisation des en-têtes et du corps. En outre, vous souhaiterez peut-être vérifier le type de contenu du corps pour la journalisation (par exemple, journaliser uniquement l'application / json *). Cela devrait également être configurable. dans l'ensemble, avec ces petits ajustements, vous aurez une belle bibliothèque à diffuser. bon travail :)Je voulais également ajouter ma mise en œuvre de cela. Je m'excuse pour tous les points-virgules manquants, c'est écrit en Groovy.
J'avais besoin de quelque chose de plus configurable que la réponse acceptée fournie. Voici un bean de modèle de repos qui est très agile et enregistrera tout ce que l'OP recherche.
Classe d'interception de journalisation personnalisée:
Définition du bean Rest Template:
La mise en oeuvre:
la source
Référez-vous au Q / A pour enregistrer la demande et la réponse pour le modèle de repos en activant les lectures multiples sur le HttpInputStream
Pourquoi mon ClientHttpRequestInterceptor personnalisé avec une réponse vide
la source
org.apache.http.wire donne des journaux trop illisibles, donc j'utilise logbook pour enregistrer l'application Servlet et RestTemplate req / resp pour se connecter
build.gradle
application.properties
RestTemplate
la source
En ce qui concerne la réponse à l'aide de ClientHttpInterceptor, j'ai trouvé un moyen de conserver la réponse entière sans tamponner les usines. Il suffit de stocker le flux d'entrée du corps de réponse dans le tableau d'octets à l'aide d'une méthode utils qui copiera ce tableau du corps, mais important, entourez cette méthode de try catch car elle se cassera si la réponse est vide (c'est la cause de l'exception d'accès aux ressources) et dans catch, créez simplement un tableau d'octets vide et créez simplement une classe interne anonyme de ClientHttpResponse en utilisant ce tableau et d'autres paramètres de la réponse d'origine. Vous pouvez ensuite renvoyer ce nouvel objet ClientHttpResponse à la chaîne d'exécution du modèle de repos et vous pouvez consigner la réponse à l'aide du tableau d'octets du corps qui est précédemment stocké. De cette façon, vous éviterez de consommer InputStream dans la réponse réelle et vous pourrez utiliser la réponse Rest Template comme elle est. Remarque,
la source
ma configuration de l'enregistreur a utilisé xml
alors vous obtiendrez quelque chose comme ci-dessous:
via HttpMessageConverterExtractor.java:92, vous devez continuer à déboguer, et dans mon cas, j'ai obtenu ceci:
et ça:
outputMessage.getBody () contient le message envoyé par http (type de message)
la source