He estado usando Spring RestTemplate durante un tiempo y constantemente me encuentro con un muro cuando intento depurar sus solicitudes y respuestas. Básicamente, estoy buscando ver las mismas cosas que veo cuando uso curl con la opción "detallada" activada. Por ejemplo :
curl -v http://twitter.com/statuses/public_timeline.rss
Mostraría tanto los datos enviados como los datos recibidos (incluidos los encabezados, las cookies, etc.).
He revisado algunas publicaciones relacionadas como: ¿Cómo registro la respuesta en Spring RestTemplate? pero no he logrado resolver este problema.
Una forma de hacer esto sería cambiar el código fuente de RestTemplate y agregar algunas declaraciones de registro adicionales allí, pero creo que este enfoque es realmente el último recurso. Debería haber alguna forma de decirle a Spring Web Client / RestTemplate que registre todo de una manera mucho más amigable.
Mi objetivo sería poder hacer esto con código como:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
y luego obtener el mismo tipo de información de depuración (como obtengo con curl) en el archivo de registro o en la consola. Creo que esto sería extremadamente útil para cualquiera que use Spring RestTemplate y tenga problemas. Usar curl para depurar sus problemas de RestTemplate simplemente no funciona (en algunos casos).
fuente
Respuestas:
Solo para completar el ejemplo con una implementación completa de
ClientHttpRequestInterceptor
rastrear solicitud y respuesta:Luego instanciar
RestTemplate
usando aBufferingClientHttpRequestFactory
y elLoggingRequestInterceptor
:Se
BufferingClientHttpRequestFactory
requiere como queremos usar el cuerpo de respuesta tanto en el interceptor como para el código de llamada inicial. La implementación predeterminada permite leer el cuerpo de la respuesta solo una vez.fuente
BufferingClientHttpResponseWrapper
como @sofienezaghdoudi implica. Sin embargo, no funciona cuando se usa en pruebas que usan el marco de trabajo mockServer de spring, ya queMockRestServiceServer.createServer(restTemplate)
sobrescribe RequestFactory enInterceptingClientHttpRequestFactory
.en Spring Boot puede obtener la solicitud / respuesta completa configurando esto en propiedades (u otro método de 12 factores)
esto produce
y respuesta
o simplemente
logging.level.org.apache.http.wire=DEBUG
que parece contener toda la información relevantefuente
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]
Extendiendo la respuesta @hstoerr con algún código:
Crear LoggingRequestInterceptor para registrar respuestas de solicitudes
Configurar RestTemplate
fuente
Su mejor opción es agregar
logging.level.org.springframework.web.client.RestTemplate=DEBUG
alapplication.properties
archivo.Otras soluciones como la configuración
log4j.logger.httpclient.wire
no siempre funcionarán porque suponen que usalog4j
ApacheHttpClient
, lo que no siempre es cierto.Sin embargo, tenga en cuenta que esta sintaxis solo funcionará en las últimas versiones de Spring Boot.
fuente
wire
registro, que sólo incluye información esencial como url, código resepone, etc. parámetros POSTNinguna de estas respuestas realmente resuelve el 100% del problema. mjj1409 obtiene la mayor parte, pero evita convenientemente el problema de registrar la respuesta, lo que requiere un poco más de trabajo. Paul Sabou proporciona una solución que parece realista, pero no proporciona suficientes detalles para implementar realmente (y no funcionó en absoluto para mí). Sofiene consiguió el registro pero con un problema crítico: ¡la respuesta ya no es legible porque el flujo de entrada ya se ha consumido!
Recomiendo usar un BufferingClientHttpResponseWrapper para ajustar el objeto de respuesta para permitir leer el cuerpo de la respuesta varias veces:
Esto no consumirá InputStream porque el cuerpo de respuesta se carga en la memoria y se puede leer varias veces. Si no tiene el BufferingClientHttpResponseWrapper en su classpath, puede encontrar la implementación simple aquí:
https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
Para configurar RestTemplate:
fuente
status==200
, antesresponseCopy.getBody()
asyncRestTemplate
? Debería devolver unListenableFuture
mensaje cuando lo intercepte, lo que no es posible alterarBufferingClientHttpResponseWrapper
en una devolución de llamada.La solución dada por xenoterracide para usar
es bueno, pero el problema es que, por defecto, Apache HttpComponents no se usa.
Para usar Apache HttpComponents agregue a su pom.xml
y configurar
RestTemplate
con:fuente
Puede usar spring-rest-template-logger para registrar el
RestTemplate
tráfico HTTP.Agregue una dependencia a su proyecto Maven:
Luego personalice su de la
RestTemplate
siguiente manera:Asegúrese de que el registro de depuración esté habilitado en
application.properties
:Ahora todo el tráfico HTTP de RestTemplate se registrará
org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
en el nivel de depuración.DESCARGO DE RESPONSABILIDAD: Escribí esta biblioteca.
fuente
Finalmente encontré una manera de hacer esto de la manera correcta. La mayor parte de la solución proviene de ¿Cómo configuro Spring y SLF4J para que pueda iniciar sesión?
Parece que hay dos cosas que deben hacerse:
log4j.logger.httpclient.wire=DEBUG
El segundo problema ocurre principalmente en entornos de primavera donde se usa slf4j (como fue mi caso). Como tal, cuando se usa slf4j, asegúrese de que sucedan las siguientes dos cosas:
No hay una biblioteca de registro de comunes en su classpath: esto se puede hacer agregando los descriptores de exclusión en su pom:
El archivo log4j.properties se almacena en algún lugar del classpath donde spring puede encontrarlo / verlo. Si tiene problemas con esto, una solución de último recurso sería colocar el archivo log4j.properties en el paquete predeterminado (no es una buena práctica, pero solo para ver que las cosas funcionan como espera)
fuente
httpclient.wire
en realidad es de la biblioteca Apache HttpComponents HttpClient (consulte hc.apache.org/httpcomponents-client-ga/logging.html ). Esta técnica solo funcionará si haRestTemplate
configurado el uso deHttpComponentsClientHttpRequestFactory
Registro RestTemplate
Opción 1. Abra el registro de depuración.
Configurar RestTemplate
Por defecto, RestTemplate se basa en las instalaciones estándar de JDK para establecer conexiones HTTP. Puede cambiar para usar una biblioteca HTTP diferente, como Apache HttpComponents
@Bean public RestTemplate restTemplate (constructor RestTemplateBuilder) {RestTemplate restTemplate = builder.build (); return restTemplate; }
Configurar registro
application.yml
registro: nivel: org.springframework.web.client.RestTemplate: DEBUG
Opción 2. Uso del interceptor
Respuesta del envoltorio
Implementar interceptor
Configurar RestTemplate
Configurar registro
Comprobar el paquete de LoggingRestTemplate, por ejemplo en
application.yml
:logging: level: com.example.logging: DEBUG
Opción 3. Usar httpcomponent
Importar dependencia de componente http
Configurar RestTemplate
Configurar registro
Comprobar el paquete de LoggingRestTemplate, por ejemplo en
application.yml
:registro: nivel: org.apache.http: DEBUG
fuente
TestRestTemplate
, configureRestTemplateBuilder
: @Bean public RestTemplateBuilder restTemplateBuilder () {return new RestTemplateBuilder (). AdditionalInterceptors (Collections.singletonList (new LoggingRestTemplate ())); }---- Julio 2019 ----
(usando Spring Boot)
Me sorprendió que Spring Boot, con toda su magia de Configuración Cero, no proporciona una manera fácil de inspeccionar o registrar un cuerpo de respuesta JSON simple con RestTemplate. Revisé las diferentes respuestas y comentarios proporcionados aquí, y comparto mi propia versión destilada de lo que (todavía) funciona y me parece una solución razonable, dadas las opciones actuales (estoy usando Spring Boot 2.1.6 con Gradle 4.4 )
1. Usando Fiddler como proxy HTTP
En realidad, esta es una solución bastante elegante, ya que evita todos los esfuerzos engorrosos de crear su propio interceptor o cambiar el cliente http subyacente a apache (ver más abajo).
y entonces
2. Usando Apache HttpClient
Agregue Apache HttpClient a sus dependencias Maven o Gradle.
Usar
HttpComponentsClientHttpRequestFactory
como RequestFactory para RestTemplate. La forma más sencilla de hacerlo sería:Habilite DEBUG en su
application.properties
archivo (si está usando Spring Boot)Si está utilizando Spring Boot, deberá asegurarse de tener un marco de registro configurado, por ejemplo, mediante el uso de una dependencia spring-boot-starter que incluya
spring-boot-starter-logging
.3. Use un interceptor
Te dejaré leer las propuestas, contrapropuestas y trucos en las otras respuestas y comentarios y decidir por ti mismo si quieres seguir ese camino.
4. URL de registro y estado de respuesta sin cuerpo
Aunque esto no cumple con los requisitos establecidos para registrar el cuerpo, es una forma rápida y sencilla de comenzar a registrar sus llamadas REST. Muestra la URL completa y el estado de respuesta.
Simplemente agregue la siguiente línea a su
application.properties
archivo (suponiendo que esté utilizando Spring Boot, y suponiendo que está utilizando una dependencia de inicio de arranque de Spring que incluyespring-boot-starter-logging
)La salida se verá más o menos así:
fuente
Además del registro de HttpClient descrito en la otra respuesta , también puede introducir un ClientHttpRequestInterceptor que lee el cuerpo de la solicitud y la respuesta y lo registra. Es posible que desee hacer esto si otras cosas también usan el HttpClient, o si desea un formato de registro personalizado. Precaución: querrá darle a RestTemplate un BufferingClientHttpRequestFactory para que pueda leer la respuesta dos veces.
fuente
Como se indicó en las otras respuestas, el cuerpo de la respuesta necesita un tratamiento especial para que pueda leerse repetidamente (por defecto, su contenido se consume en la primera lectura).
En lugar de utilizar el
BufferingClientHttpRequestFactory
al configurar la solicitud, el propio interceptor puede ajustar la respuesta y asegurarse de que el contenido se conserve y pueda leerse repetidamente (tanto por el registrador como por el consumidor de la respuesta):Mi interceptor, que
Código:
Configuración:
Ejemplo de salida de registro:
fuente
application.properties
application.yml
fuente
Puede que esta no sea la forma correcta de hacerlo, pero creo que este es el enfoque más simple para imprimir solicitudes y respuestas sin llenar demasiado los registros.
Al agregar debajo de 2 líneas, application.properties registra todas las solicitudes y respuestas en la primera línea para registrar las solicitudes y en la segunda línea para registrar las respuestas.
fuente
Suponiendo que
RestTemplate
esté configurado para usar HttpClient 4.x, puede leer la documentación de registro de HttpClient aquí . Los registradores son diferentes a los especificados en las otras respuestas.La configuración de registro para HttpClient 3.x está disponible aquí .
fuente
Tantas respuestas aquí requieren cambios de codificación y clases personalizadas y realmente no es necesario. Obtenga un proxy de depuración como fiddler y configure su entorno java para usar el proxy en la línea de comando (-Dhttp.proxyHost y -Dhttp.proxyPort) luego ejecute fiddler y podrá ver las solicitudes y respuestas en su totalidad. También viene con muchas ventajas auxiliares, como la capacidad de modificar los resultados y las respuestas antes y después de enviarlos a ejecutar experimentos antes de comprometerse a modificar el servidor.
El último problema que puede surgir es que si debe usar HTTPS, deberá exportar el certificado SSL desde el violinista e importarlo en la clave del almacén de claves de Java (cacerts): la contraseña predeterminada del almacén de claves de Java suele ser "changeit".
fuente
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888
.Para iniciar sesión en Logback con la ayuda de Apache HttpClient:
Necesita Apache HttpClient en classpath:
Configure su
RestTemplate
para usar HttpClient:Para registrar solicitudes y respuestas, agregue al archivo de configuración Logback:
O para iniciar sesión aún más:
fuente
org.apache.http.wire=DEBUG
en tuapplication.properties
ahoraEl truco de configurar su
RestTemplate
con unBufferingClientHttpRequestFactory
no funciona si está utilizando algunoClientHttpRequestInterceptor
, lo que hará si está intentando iniciar sesión a través de interceptores. Esto se debe a la forma en que funcionaInterceptingHttpAccessor
(quéRestTemplate
subclases).Larga historia corta ... solo use esta clase en lugar de
RestTemplate
(tenga en cuenta que esto usa la API de registro SLF4J, edite según sea necesario):Estoy de acuerdo en que es una tontería que se necesita tanto trabajo solo para hacer esto.
fuente
Además de la discusión anterior, esto solo representa escenarios felices. probablemente no podrá registrar la respuesta si se produce un error .
En este caso, más todos los casos anteriores, debe anular DefaultResponseErrorHandler y configurarlo como se muestra a continuación
fuente
Curiosamente, ninguna de estas soluciones funciona ya que RestTemplate no parece devolver la respuesta en algunos errores 500x de clientes y servidores. En ese caso, también tendrá que registrarlos implementando ResponseErrorHandler de la siguiente manera. Aquí hay un borrador de código, pero entiendes el punto:
Puede configurar el mismo interceptor que el controlador de errores:
Y la intercepción implementa ambas interfaces:
fuente
Como señaló @MilacH, hay un error en la implementación. Si se devuelve un statusCode> 400, se lanza una IOException, ya que no se invoca el errorHandler, desde los interceptores. La excepción se puede ignorar y luego se vuelve a detectar en el método del controlador.
fuente
La mejor solución ahora, solo agrega dependencia:
Contiene una clase LoggingRequestInterceptor que puede agregar de esa manera a su RestTemplate:
integre esta utilidad agregándola como un interceptor a un RestTemplate de resorte, de la siguiente manera:
y agregue una implementación slf4j a su marco como log4j.
o use directamente "Zg2proRestTemplate" . La "mejor respuesta" de @PaulSabou lo parece, ya que httpclient y todas las bibliotecas apache.http no se cargan necesariamente cuando se utiliza un Spring RestTemplate.
fuente
log("Headers: {}", request.headers)
adentroLoggingRequestInterceptor:traceRequest
ylog("Headers: {}", response.headers)
adentroLoggingRequestInterceptor:logResponse
. Es posible que desee pensar en agregar algunas banderas para registrar encabezados y cuerpo. Además, es posible que desee verificar el tipo de contenido del cuerpo para el registro (por ejemplo, registrar solo la aplicación / json *). Esto también debería ser configurable. en general, con esos pequeños ajustes tendrás una buena biblioteca para difundir. buen trabajo :)Quería agregar mi implementación de esto también. Pido disculpas por todos los puntos y coma que faltan, esto está escrito en Groovy.
Necesitaba algo más configurable que la respuesta aceptada proporcionada. Aquí hay un bean de plantilla de descanso que es muy ágil y registrará todo lo que el OP está buscando.
Clase de interceptor de registro personalizado:
Definición de frijol de plantilla de descanso:
Implementación:
fuente
Consulte las preguntas y respuestas para registrar la solicitud y la respuesta para la plantilla de descanso habilitando las lecturas múltiples en HttpInputStream
¿Por qué mi ClientHttpRequestInterceptor personalizado con respuesta vacía?
fuente
org.apache.http.wire proporciona registros demasiado ilegibles, por lo que uso el libro de registro para registrar la aplicación Servlet y RestTemplate req / resp para registrar
build.gradle
application.properties
RestTemplate
fuente
En relación con la respuesta usando ClientHttpInterceptor, encontré una forma de mantener toda la respuesta sin las fábricas de Buffering. Simplemente almacene la secuencia de entrada del cuerpo de respuesta dentro de la matriz de bytes utilizando algún método de utilidades que copiará esa matriz del cuerpo, pero importante, rodee este método con try catch porque se romperá si la respuesta está vacía (esa es la causa de la excepción de acceso a recursos) y en catch solo cree una matriz de bytes vacía, y luego simplemente cree una clase interna anónima de ClientHttpResponse usando esa matriz y otros parámetros de la respuesta original. Luego, puede devolver ese nuevo objeto ClientHttpResponse a la cadena de ejecución de la plantilla del resto y puede registrar la respuesta utilizando la matriz de bytes del cuerpo que se almacenó previamente. De esta forma evitará consumir InputStream en la respuesta real y puede usar la respuesta de la plantilla de descanso tal como está. Nota,
fuente
mi configuración de registrador usó xml
entonces obtendrás algo como a continuación:
a través de HttpMessageConverterExtractor.java:92, necesita continuar depurando, y en mi caso, obtuve esto:
y esto:
outputMessage.getBody () contiene el mensaje que envía http (tipo de publicación)
fuente