Używam Spring RestTemplate od jakiegoś czasu i konsekwentnie uderzam w ścianę, gdy próbuję debugować jego żądania i odpowiedzi. Zasadniczo chcę zobaczyć te same rzeczy, co widzę, gdy używam curl z włączoną opcją „verbose”. Na przykład :
curl -v http://twitter.com/statuses/public_timeline.rss
Wyświetla zarówno przesłane dane, jak i otrzymane dane (w tym nagłówki, pliki cookie itp.).
Sprawdziłem kilka pokrewnych postów, takich jak: Jak zalogować odpowiedź w Spring RestTemplate? ale nie udało mi się rozwiązać tego problemu.
Jednym ze sposobów, aby to zrobić, jest zmiana kodu źródłowego RestTemplate i dodanie tam dodatkowych instrukcji logowania, ale uważam, że takie podejście jest naprawdę ostatecznością. Powinien istnieć sposób, aby poinformować Spring Web Client / RestTemplate, aby rejestrował wszystko w znacznie bardziej przyjazny sposób.
Moim celem byłoby, aby móc to zrobić za pomocą kodu takiego jak:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
a następnie uzyskać ten sam typ informacji debugowania (jak w przypadku curl) w pliku dziennika lub w konsoli. Uważam, że byłoby to niezwykle przydatne dla każdego, kto używa Spring RestTemplate i ma problemy. Używanie curl do debugowania problemów z RestTemplate po prostu nie działa (w niektórych przypadkach).
źródło
Odpowiedzi:
Wystarczy uzupełnić przykład pełną implementacją
ClientHttpRequestInterceptor
śledzenia żądania i odpowiedzi:Następnie utwórz instancję
RestTemplate
za pomocą aBufferingClientHttpRequestFactory
iLoggingRequestInterceptor
:Jest
BufferingClientHttpRequestFactory
to wymagane, ponieważ chcemy użyć treści odpowiedzi zarówno w przechwytywaczu, jak i w początkowym kodzie wywoławczym. Domyślna implementacja pozwala odczytać treść odpowiedzi tylko raz.źródło
BufferingClientHttpResponseWrapper
@sofienezaghdoudi. Jednak nie działa, gdy jest używany w testach z wykorzystaniem wiosennego środowiska mockServer, ponieważMockRestServiceServer.createServer(restTemplate)
zastępuje obiekt RequestFactoryInterceptingClientHttpRequestFactory
.w Spring Boot można uzyskać pełne żądanie / odpowiedź, ustawiając to we właściwościach (lub innej 12-czynnikowej metodzie)
to wychodzi
i odpowiedź
lub po prostu,
logging.level.org.apache.http.wire=DEBUG
które wydają się zawierać wszystkie istotne informacjeźródło
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]
Rozszerzenie odpowiedzi @hstoerr o kod:
Utwórz LoggingRequestInterceptor, aby rejestrować odpowiedzi na żądania
Skonfiguruj szablon RestTemplate
źródło
Najlepszym rozwiązaniem jest dodanie
logging.level.org.springframework.web.client.RestTemplate=DEBUG
doapplication.properties
pliku.Inne rozwiązania, takie jak ustawienie
log4j.logger.httpclient.wire
, nie zawsze będą działać, ponieważ zakładają, że używaszlog4j
i ApacheHttpClient
, co nie zawsze jest prawdą.Należy jednak pamiętać, że ta składnia będzie działać tylko w najnowszych wersjach Spring Boot.
źródło
wire
rejestrowanie, zawiera tylko niezbędne informacje, takie jak adres URL, kod odesłany, parametry POST itp.Żadna z tych odpowiedzi nie rozwiązuje w 100% problemu. mjj1409 otrzymuje większość, ale wygodnie unika się problemu z rejestrowaniem odpowiedzi, co zajmuje nieco więcej pracy. Paul Sabou zapewnia rozwiązanie, które wydaje się realistyczne, ale nie zawiera wystarczających szczegółów do faktycznego wdrożenia (i dla mnie to w ogóle nie zadziałało). Sofiene dostała rejestrację, ale z krytycznym problemem: odpowiedź nie jest już czytelna, ponieważ strumień wejściowy został już wykorzystany!
Polecam użycie BufferingClientHttpResponseWrapper do zawinięcia obiektu odpowiedzi, aby umożliwić wielokrotne czytanie treści odpowiedzi:
Nie spowoduje to zużycia InputStream, ponieważ treść odpowiedzi jest ładowana do pamięci i może być odczytywana wiele razy. Jeśli nie masz BufferingClientHttpResponseWrapper na ścieżce klasy, możesz znaleźć prostą implementację tutaj:
https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
Aby skonfigurować RestTemplate:
źródło
status==200
wcześniejresponseCopy.getBody()
asyncRestTemplate
? Wymagane będzie zwrócenie znaku,ListenableFuture
gdy go przechwycisz, czego nie można zmienićBufferingClientHttpResponseWrapper
w wywołaniu zwrotnym.Do rejestrowania ruchu HTTP można użyć narzędzia Spring-rest-template-logger
RestTemplate
.Dodaj zależność do swojego projektu Maven:
Następnie dostosuj
RestTemplate
w następujący sposób:Upewnij się, że rejestrowanie debugowania jest włączone w
application.properties
:Teraz cały ruch HTTP RestTemplate zostanie zalogowany
org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
na poziomie debugowania.ZASTRZEŻENIE: Napisałem tę bibliotekę.
źródło
Rozwiązanie podane przez ksenoterracid do użycia
jest dobry, ale problem polega na tym, że domyślnie Apache HttpComponents nie jest używany.
Aby użyć Apache HttpComponents, dodaj do pliku pom.xml
i skonfiguruj za
RestTemplate
pomocą:źródło
W końcu znalazłem sposób na zrobienie tego we właściwy sposób. Większość rozwiązań pochodzi z Jak skonfigurować Spring i SLF4J, aby uzyskać logowanie?
Wydaje się, że należy zrobić dwie rzeczy:
log4j.logger.httpclient.wire=DEBUG
Drugi problem dotyczy głównie środowisk wiosennych, w których używany jest slf4j (tak jak w moim przypadku). Jako taki, gdy używany jest slf4j, upewnij się, że zachodzą następujące dwie rzeczy:
W ścieżce klasy nie ma biblioteki rejestrowania wspólnych: można to zrobić, dodając deskryptory wykluczeń w pom:
Plik log4j.properties jest przechowywany gdzieś w ścieżce klasy, gdzie wiosna może go znaleźć / zobaczyć. Jeśli masz z tym problemy, rozwiązaniem ostatecznym byłoby umieszczenie pliku log4j.properties w domyślnym pakiecie (nie jest to dobra praktyka, ale po prostu sprawdza, czy wszystko działa zgodnie z oczekiwaniami)
źródło
httpclient.wire
pochodzi z biblioteki Apache HttpComponents HttpClient (patrz hc.apache.org/httpcomponents-client-ga/logging.html ). Ta technika zadziała tylko, jeśliRestTemplate
skonfigurowałeśHttpComponentsClientHttpRequestFactory
Rejestrowanie RestTemplate
Opcja 1. Otwórz rejestrowanie debugowania.
Skonfiguruj RestTemplate
Domyślnie RestTemplate opiera się na standardowych funkcjach JDK do nawiązywania połączeń HTTP. Możesz przełączyć się na używanie innej biblioteki HTTP, takiej jak Apache HttpComponents
@Bean public RestTemplate restTemplate (konstruktor RestTemplateBuilder) {RestTemplate restTemplate = builder.build (); return restTemplate; }
Skonfiguruj rejestrowanie
application.yml
logowanie: poziom: org.springframework.web.client.RestTemplate: DEBUG
Opcja 2. Korzystanie z przechwytywacza
Odpowiedź opakowania
Wdrożenie przechwytywacza
Skonfiguruj RestTemplate
Skonfiguruj rejestrowanie
Sprawdź pakiet LoggingRestTemplate, na przykład w
application.yml
:logowanie: poziom: com.example.logging: DEBUG
Opcja 3. Korzystanie z komponentu http
Importuj zależność httpomponent
Skonfiguruj RestTemplate
Skonfiguruj rejestrowanie
Sprawdź pakiet LoggingRestTemplate, na przykład w
application.yml
:logowanie: poziom: org.apache.http: DEBUG
źródło
TestRestTemplate
, skonfigurujRestTemplateBuilder
: @Bean public RestTemplateBuilder restTemplateBuilder () {return new RestTemplateBuilder (). AdditionalInterceptors (Collections.singletonList (new LoggingRestTemplate ())); }---- lipiec 2019 ----
(przy użyciu Spring Boot)
Byłem zaskoczony, że Spring Boot, z całą magią konfiguracji zerowej, nie zapewnia łatwego sposobu na sprawdzenie lub zalogowanie prostej odpowiedzi JSON za pomocą RestTemplate. Przejrzałem różne podane tutaj odpowiedzi i komentarze i dzielę się własną destylowaną wersją tego, co (nadal) działa i wydaje mi się rozsądnym rozwiązaniem, biorąc pod uwagę obecne opcje (używam Spring Boot 2.1.6 z Gradle 4.4 )
1. Używanie Fiddlera jako proxy HTTP
Jest to w rzeczywistości dość eleganckie rozwiązanie, ponieważ omija wszystkie uciążliwe wysiłki związane z tworzeniem własnego przechwytywacza lub zmianą klienta HTTP na apache (patrz poniżej).
i wtedy
2. Korzystanie z Apache HttpClient
Dodaj Apache HttpClient do swoich zależności Maven lub Gradle.
Użyj
HttpComponentsClientHttpRequestFactory
jako RequestFactory dla RestTemplate. Najprostszym sposobem na to byłoby:Włącz DEBUGĘ w swoim
application.properties
pliku (jeśli używasz Spring Boot)Jeśli korzystasz z Spring Boot, musisz upewnić się, że masz skonfigurowane środowisko rejestrowania, np. Używając zależności obejmującej rozruch rozruchowy
spring-boot-starter-logging
.3. Użyj przechwytywacza
Pozwolę ci przeczytać propozycje, kontr-propozycje i gotchas w innych odpowiedziach i komentarzach i sam zdecydować, czy chcesz pójść tą ścieżką.
4. Adres URL dziennika i stan odpowiedzi bez treści
Chociaż nie spełnia to określonych wymagań dotyczących rejestrowania treści, jest to szybki i prosty sposób na rozpoczęcie rejestrowania połączeń REST. Wyświetla pełny adres URL i status odpowiedzi.
Po prostu dodaj następujący wiersz do swojego
application.properties
pliku (zakładając, że używasz Spring Boot, i zakładając, że używasz zależności rozruchowej Spring, która obejmujespring-boot-starter-logging
)Dane wyjściowe będą wyglądać mniej więcej tak:
źródło
Oprócz rejestrowania HttpClient opisanego w drugiej odpowiedzi można również wprowadzić ClientHttpRequestInterceptor, który odczytuje treść żądania i odpowiedź oraz rejestruje je. Możesz to zrobić, jeśli inne rzeczy również korzystają z HttpClient lub jeśli chcesz niestandardowego formatu rejestrowania. Uwaga: powinieneś nadać RestTemplate BufferingClientHttpRequestFactory, abyś mógł przeczytać odpowiedź dwa razy.
źródło
Jak stwierdzono w innych odpowiedziach, ciało odpowiedzi wymaga specjalnego traktowania, aby można było go wielokrotnie czytać (domyślnie jego zawartość jest konsumowana przy pierwszym czytaniu).
Zamiast używać
BufferingClientHttpRequestFactory
podczas konfigurowania żądania, sam przechwytujący może zawinąć odpowiedź i upewnić się, że treść jest zachowana i może być wielokrotnie odczytywana (zarówno przez program rejestrujący, jak i przez konsumenta odpowiedzi):Mój przechwytujący, który
Kod:
Konfiguracja:
Przykładowe dane wyjściowe dziennika:
źródło
application.properties
application.yml
źródło
Może to nie być właściwy sposób, ale myślę, że jest to najprostsze podejście do drukowania żądań i odpowiedzi bez wypełniania zbyt dużej ilości dzienników.
Dodając poniżej 2 wierszy application.properties rejestruje wszystkie żądania i odpowiedzi 1. wiersz w celu zarejestrowania żądań i 2. wiersz w celu zarejestrowania odpowiedzi.
źródło
Zakładając, że
RestTemplate
jest skonfigurowany do używania HttpClient 4.x, możesz przeczytać dokumentację rejestrowania HttpClient tutaj . Rejestratory różnią się od tych określonych w innych odpowiedziach.Konfiguracja rejestrowania dla HttpClient 3.x jest dostępna tutaj .
źródło
Tak wiele odpowiedzi tutaj wymaga zmian w kodowaniu i dostosowanych klas i to naprawdę nie jest konieczne. Pobierz debugujący serwer proxy, taki jak skrzypek, i skonfiguruj środowisko Java, aby korzystało z serwera proxy w wierszu poleceń (-Dhttp.proxyHost i -Dhttp.proxyPort), a następnie uruchom skrzynkę i możesz zobaczyć żądania i odpowiedzi w całości. Ma również wiele dodatkowych zalet, takich jak możliwość majstrowania przy wynikach i odpowiedziach przed i po wysłaniu ich w celu przeprowadzenia eksperymentów przed przystąpieniem do modyfikacji serwera.
Ostatni problem, który może się pojawić, jeśli musisz użyć HTTPS, musisz wyeksportować certyfikat SSL ze skrzypka i zaimportować go do magazynu kluczy Java (cacerts). Wskazówka: domyślne hasło do pliku kluczy Java to zwykle „zmień”.
źródło
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888
.Do logowania do Logback przy pomocy Apache HttpClient:
Potrzebujesz Apache HttpClient w ścieżce klasy:
Skonfiguruj
RestTemplate
do używania HttpClient:Aby rejestrować żądania i odpowiedzi, dodaj do pliku konfiguracyjnego Logback:
Lub zalogować jeszcze więcej:
źródło
org.apache.http.wire=DEBUG
w twoimapplication.properties
terazSztuczka polegająca na skonfigurowaniu
RestTemplate
za pomocąBufferingClientHttpRequestFactory
nie działa, jeśli używasz takiegoClientHttpRequestInterceptor
, co zrobisz, jeśli próbujesz zalogować się za pomocą przechwytywaczy. Wynika to ze sposobu, któryInterceptingHttpAccessor
(któryRestTemplate
podklasy) działa.Krótko mówiąc ... po prostu użyj tej klasy zamiast
RestTemplate
(pamiętaj, że używa interfejsu API rejestrowania SLF4J, edytuj w razie potrzeby):Zgadzam się, że to głupie, że tyle pracy zajmuje tylko to.
źródło
Dodanie do powyższej dyskusji to tylko scenariusze Happy. prawdopodobnie nie będziesz w stanie zarejestrować odpowiedzi, jeśli wystąpi błąd .
W tym przypadku plus wszystkie powyższe przypadki musisz zastąpić DefaultResponseErrorHandler i ustawić go jak poniżej
źródło
O dziwo, żadne z tych rozwiązań nie działa, ponieważ wydaje się, że RestTemplate nie zwraca odpowiedzi na niektóre błędy 500x klienta i serwera. W takim przypadku należy je również zarejestrować, implementując ResponseErrorHandler w następujący sposób. Oto szkic kodu, ale rozumiesz:
Możesz ustawić ten sam przechwytywacz jak moduł obsługi błędów:
A przechwytywanie implementuje oba interfejsy:
źródło
Jak wskazał @MilacH, w implementacji wystąpił błąd. Jeśli zostanie zwrócony kod statusu> 400, zgłoszony zostanie wyjątek IOException, ponieważ obiekt przechwytujący błędy nie jest wywoływany z przechwytywaczy. Wyjątek można zignorować, a następnie ponownie przechwycić w metodzie procedury obsługi.
źródło
Najlepsze rozwiązanie teraz, po prostu dodaj zależność:
Zawiera klasę LoggingRequestInterceptor, którą można dodać w ten sposób do RestTemplate:
zintegruj to narzędzie, dodając je jako przechwytywacz do sprężynowego elementu RestTemplate, w następujący sposób:
i dodaj implementację slf4j do swojego frameworka, np. log4j.
lub bezpośrednio użyj „Zg2proRestTemplate” . „Najlepsza odpowiedź” autorstwa @PaulSabou wygląda tak, ponieważ biblioteki httpclient i wszystkie biblioteki apache.http niekoniecznie są ładowane podczas korzystania ze sprężynowego szablonu RestTemplate.
źródło
log("Headers: {}", request.headers)
inLoggingRequestInterceptor:traceRequest
ilog("Headers: {}", response.headers)
inLoggingRequestInterceptor:logResponse
. Możesz pomyśleć o dodaniu niektórych flag do rejestrowania nagłówków i treści. Ponadto - możesz sprawdzić typ zawartości treści do rejestrowania (na przykład rejestruj tylko aplikację / json *). To powinno być również konfigurowalne. Podsumowując, dzięki tym drobnym poprawkom będziesz mieć przyjemną bibliotekę do rozpowszechnienia. dobra robota :)Chciałem również dodać moją implementację tego. Przepraszam za wszystkie brakujące średniki, to jest napisane w Groovy.
Potrzebowałem czegoś bardziej konfigurowalnego niż podana zaakceptowana odpowiedź. Oto pozostałe szablony bean, które są bardzo zwinne i będą rejestrować wszystko tak, jak szuka OP.
Niestandardowa klasa przechwytywania rejestrowania:
Definicja szablonu fasoli:
Realizacja:
źródło
Zapoznaj się z pytaniem / pytaniem w sprawie rejestrowania żądania i odpowiedzi dla szablonu reszty poprzez włączenie wielu odczytów w HttpInputStream
Dlaczego mój niestandardowy ClientHttpRequestInterceptor z pustą odpowiedzią
źródło
org.apache.http.wire dają zbyt nieczytelne logi, więc używam logbooka do rejestrowania aplikacji Servlet i RestTemplate req / resp do logowania
build.gradle
application.properties
RestTemplate
źródło
W związku z odpowiedzią za pomocą ClientHttpInterceptor znalazłem sposób na zachowanie całej odpowiedzi bez buforowania fabryk. Wystarczy zapisać strumień wejściowy treści odpowiedzi w tablicy bajtów za pomocą metody utils, która skopiuje tę tablicę z treści, ale ważne jest, aby otoczyć tę metodę metodą try catch, ponieważ pęknie, jeśli odpowiedź będzie pusta (to jest przyczyną wyjątku dostępu do zasobów) i w catch po prostu utwórz pustą tablicę bajtów, a następnie po prostu stwórz anonimową klasę wewnętrzną ClientHttpResponse przy użyciu tej tablicy i innych parametrów z oryginalnej odpowiedzi. Następnie możesz zwrócić ten nowy obiekt ClientHttpResponse do łańcucha wykonawczego pozostałych szablonów i możesz zarejestrować odpowiedź, używając wcześniej zapisanej tablicy bajtów treści. W ten sposób unikniesz zużycia InputStream w rzeczywistej odpowiedzi i możesz użyć odpowiedzi Rest Template w takiej formie, w jakiej jest. Uwaga,
źródło
moja konfiguracja loggera używała xml
wtedy otrzymasz coś takiego:
przez HttpMessageConverterExtractor.java:92, musisz kontynuować debugowanie, aw moim przypadku mam to:
i to:
outputMessage.getBody () zawiera komunikat wysyłany przez http (typ postu)
źródło