Saya telah menggunakan Spring RestTemplate untuk sementara waktu dan saya secara konsisten menabrak dinding ketika saya mencoba men-debug permintaan dan tanggapannya. Saya pada dasarnya mencari untuk melihat hal yang sama seperti yang saya lihat ketika saya menggunakan ikal dengan opsi "verbose" dihidupkan. Sebagai contoh :
curl -v http://twitter.com/statuses/public_timeline.rss
Akan menampilkan data yang dikirim dan data yang diterima (termasuk header, cookie, dll.).
Saya telah memeriksa beberapa posting terkait seperti: Bagaimana cara mencatat respons di Spring RestTemplate? tapi saya belum berhasil menyelesaikan masalah ini.
Salah satu cara untuk melakukan ini adalah dengan benar-benar mengubah kode sumber RestTemplate dan menambahkan beberapa pernyataan logging tambahan di sana, tapi saya akan menemukan pendekatan ini benar-benar hal terakhir. Seharusnya ada beberapa cara untuk memberi tahu Spring Web Client / RestTemplate untuk mencatat semuanya dengan cara yang lebih ramah.
Tujuan saya adalah dapat melakukan ini dengan kode seperti:
restTemplate.put("http://someurl", objectToPut, urlPathValues);
dan kemudian untuk mendapatkan jenis informasi debug yang sama (seperti yang saya dapatkan dengan curl) di file log atau di konsol. Saya percaya ini akan sangat berguna bagi siapa saja yang menggunakan Spring RestTemplate dan memiliki masalah. Menggunakan curl untuk men-debug masalah RestTemplate Anda tidak berfungsi (dalam beberapa kasus).
sumber
Jawaban:
Cukup untuk melengkapi contoh dengan implementasi penuh
ClientHttpRequestInterceptor
untuk melacak permintaan dan respons:Kemudian instantiate
RestTemplate
menggunakan aBufferingClientHttpRequestFactory
danLoggingRequestInterceptor
:The
BufferingClientHttpRequestFactory
diperlukan karena kami ingin menggunakan respon tubuh baik dalam pencegat dan untuk kode panggilan awal. Implementasi default memungkinkan untuk membaca badan respons hanya sekali.sumber
BufferingClientHttpResponseWrapper
seperti yang disiratkan @sofienezaghdoudi. Namun, itu tidak berfungsi ketika digunakan dalam tes menggunakan kerangka mockServer musim semi karenaMockRestServiceServer.createServer(restTemplate)
menimpa RequestFactory keInterceptingClientHttpRequestFactory
.di Spring Boot Anda bisa mendapatkan permintaan / respons penuh dengan menyetelnya di properti (atau metode 12 faktor lainnya)
output ini
dan tanggapan
atau
logging.level.org.apache.http.wire=DEBUG
yang sepertinya mengandung semua informasi yang relevansumber
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]
Memperluas jawaban @hstoerr dengan beberapa kode:
Buat LoggingRequestInterceptor untuk mencatat respons permintaan
Setup RestTemplate
sumber
Taruhan terbaik Anda adalah menambahkan
logging.level.org.springframework.web.client.RestTemplate=DEBUG
keapplication.properties
file.Solusi lain seperti pengaturan
log4j.logger.httpclient.wire
tidak akan selalu berhasil karena mereka menganggap Anda menggunakanlog4j
dan ApacheHttpClient
, yang tidak selalu benar.Namun, perhatikan bahwa sintaks ini hanya akan berfungsi pada versi terbaru dari Spring Boot.
sumber
wire
logging, ini hanya mencakup informasi penting seperti url, kode resepone, parameter POST dll.Tidak satu pun dari jawaban ini yang benar-benar menyelesaikan 100% masalah. mjj1409 mendapatkan sebagian besar darinya, tetapi dengan mudah menghindari masalah logging respons, yang membutuhkan sedikit lebih banyak pekerjaan. Paul Sabou memberikan solusi yang tampaknya realistis, tetapi tidak memberikan detail yang cukup untuk benar-benar diterapkan (dan itu tidak berhasil sama sekali bagi saya). Sofiene mendapatkan pencatatan tetapi dengan masalah kritis: responsnya tidak lagi dapat dibaca karena aliran input telah digunakan!
Saya sarankan menggunakan BufferingClientHttpResponseWrapper untuk membungkus objek respons untuk memungkinkan membaca tubuh respons beberapa kali:
Ini tidak akan mengkonsumsi InputStream karena tubuh respons dimuat ke dalam memori dan dapat dibaca beberapa kali. Jika Anda tidak memiliki BufferingClientHttpResponseWrapper di classpath Anda, Anda dapat menemukan implementasi sederhana di sini:
https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
Untuk mengatur RestTemplate:
sumber
status==200
, sebelumresponseCopy.getBody()
asyncRestTemplate
? Ini akan membutuhkan untuk mengembalikanListenableFuture
ketika Anda mencegatnya yang tidak mungkin diubah denganBufferingClientHttpResponseWrapper
dalam panggilan balik.Solusi yang diberikan oleh xenoterracide untuk digunakan
bagus tapi masalahnya adalah bahwa secara default Apache HttpComponents tidak digunakan.
Untuk menggunakan Apache HttpComponents tambahkan ke pom.xml Anda
dan konfigurasikan
RestTemplate
dengan:sumber
Anda bisa menggunakan spring-rest-template-logger untuk login
RestTemplate
lalu lintas HTTP.Tambahkan ketergantungan ke proyek Maven Anda:
Kemudian sesuaikan
RestTemplate
sebagai berikut:Pastikan bahwa debug logging diaktifkan di
application.properties
:Sekarang semua lalu lintas HTTP RestTemplate akan dicatat
org.hobsoft.spring.resttemplatelogger.LoggingCustomizer
tingkat debug.PENOLAKAN: Saya menulis perpustakaan ini.
sumber
Saya akhirnya menemukan cara untuk melakukan ini dengan cara yang benar. Sebagian besar solusi berasal dari Bagaimana cara mengkonfigurasi Spring dan SLF4J sehingga saya bisa mendapatkan logging?
Sepertinya ada dua hal yang perlu dilakukan:
log4j.logger.httpclient.wire=DEBUG
Masalah kedua kebanyakan terjadi pada lingkungan pegas di mana slf4j digunakan (seperti kasus saya). Dengan demikian, ketika slf4j digunakan pastikan bahwa dua hal berikut terjadi:
Tidak ada pustaka penebangan commons di classpath Anda: ini bisa dilakukan dengan menambahkan deskriptor pengecualian di pom Anda:
File log4j.properties disimpan di suatu tempat di classpath di mana pegas dapat menemukan / melihatnya. Jika Anda memiliki masalah dengan ini, solusi terakhir adalah dengan meletakkan file log4j.properties dalam paket default (bukan praktik yang baik tetapi hanya untuk melihat bahwa semuanya berjalan seperti yang Anda harapkan)
sumber
httpclient.wire
sebenarnya dari perpustakaan Apache HttpComponents HttpClient (lihat hc.apache.org/httpcomponents-client-ga/logging.html ). Teknik ini hanya akan berfungsi jika Anda telahRestTemplate
mengkonfigurasi untuk menggunakanHttpComponentsClientHttpRequestFactory
Log RestTemplate
Opsi 1. Buka logging debug.
Konfigurasikan RestTemplate
Secara default, RestTemplate bergantung pada fasilitas JDK standar untuk membuat koneksi HTTP. Anda dapat beralih untuk menggunakan pustaka HTTP yang berbeda seperti Apache HttpComponents
@Bean publik RestTemplate restTemplate (pembuat RestTemplateBuilder) {RestTemplate restTemplate = builder.build (); mengembalikan restTemplate; }
Konfigurasikan pencatatan
application.yml
logging: level: org.springframework.web.client.RestTemplate: DEBUG
Opsi 2. Menggunakan Interceptor
Tanggapan Wrapper
Menerapkan Interceptor
Konfigurasikan RestTemplate
Konfigurasikan pencatatan
Periksa paket LoggingRestTemplate, misalnya dalam
application.yml
:logging: level: com.example.logging: DEBUG
Opsi 3. Menggunakan httpcomponent
Impor dependensi httpcomponent
Konfigurasikan RestTemplate
Konfigurasikan pencatatan
Periksa paket LoggingRestTemplate, misalnya dalam
application.yml
:logging: level: org.apache.http: DEBUG
sumber
TestRestTemplate
, konfigurasikanRestTemplateBuilder
: @Bean public RestTemplateBuilder restTemplateBuilder () {return baru RestTemplateBuilder (). TambahanInterceptors (Collections.singletonList (new LoggingRestTemplate ())); }---- Juli 2019 ----
(menggunakan Spring Boot)
Saya terkejut bahwa Boot Spring, dengan semua sihir Konfigurasi Nol, tidak menyediakan cara mudah untuk memeriksa atau mencatat badan respons JSON sederhana dengan RestTemplate. Saya melihat melalui berbagai jawaban dan komentar yang diberikan di sini, dan saya membagikan versi suling saya sendiri tentang apa yang (masih) berfungsi dan menurut saya seperti solusi yang masuk akal, mengingat opsi saat ini (saya menggunakan Spring Boot 2.1.6 dengan Gradle 4.4 )
1. Menggunakan Fiddler sebagai proksi http
Ini sebenarnya solusi yang cukup elegan, karena mem-bypass semua upaya rumit untuk membuat interseptor Anda sendiri atau mengubah klien http yang mendasarinya menjadi apache (lihat di bawah).
lalu
2. Menggunakan Apache HttpClient
Tambahkan Apache HttpClient ke dependensi Maven atau Gradle Anda.
Gunakan
HttpComponentsClientHttpRequestFactory
sebagai RequestFactory untuk RestTemplate. Cara paling sederhana untuk melakukannya adalah:Aktifkan DEBUG di
application.properties
file Anda (jika Anda menggunakan Spring Boot)Jika Anda menggunakan Spring Boot, Anda harus memastikan bahwa Anda memiliki kerangka kerja logging, misalnya dengan menggunakan dependensi spring-boot-starter yang mencakup
spring-boot-starter-logging
.3. Gunakan Pencegat
Saya akan membiarkan Anda membaca proposal, proposal tandingan, dan mendapat jawaban di jawaban dan komentar lainnya dan memutuskan sendiri apakah Anda ingin menempuh jalan itu.
4. Log URL dan Status Respons tanpa Badan
Meskipun ini tidak memenuhi persyaratan yang disebutkan untuk mencatat badan, itu adalah cara yang cepat dan sederhana untuk mulai mencatat panggilan REST Anda. Ini menampilkan URL lengkap dan status respons.
Cukup tambahkan baris berikut ke
application.properties
file Anda (dengan asumsi Anda menggunakan Spring Boot, dan dengan asumsi Anda menggunakan dependensi starter boot spring yang mencakupspring-boot-starter-logging
)Outputnya akan terlihat seperti ini:
sumber
Selain pencatatan HttpClient yang dijelaskan dalam jawaban lain , Anda juga dapat memperkenalkan ClientHttpRequestInterceptor yang membaca isi permintaan dan respons serta mencatatnya. Anda mungkin ingin melakukan ini jika hal-hal lain juga menggunakan HttpClient, atau jika Anda menginginkan format log kustom. Perhatian: Anda ingin memberikan RestTemplate BufferingClientHttpRequestFactory sehingga Anda dapat membaca responsnya dua kali.
sumber
Seperti yang dinyatakan dalam respons lain, badan respons membutuhkan perlakuan khusus sehingga dapat dibaca berulang kali (secara default, isinya dikonsumsi pada pembacaan pertama).
Alih-alih menggunakan
BufferingClientHttpRequestFactory
saat mengatur permintaan, pencegat itu sendiri dapat membungkus respons dan memastikan konten dipertahankan dan dapat dibaca berulang kali (oleh logger serta oleh konsumen respons):Pencegat saya, yang
Kode:
Konfigurasi:
Contoh keluaran log:
sumber
properti aplikasi
application.yml
sumber
Ini mungkin bukan cara yang benar untuk melakukannya, tetapi saya pikir ini adalah pendekatan paling sederhana untuk mencetak permintaan dan tanggapan tanpa mengisi terlalu banyak dalam log.
Dengan menambahkan di bawah 2 baris application.properties mencatat semua permintaan dan tanggapan baris ke-1 untuk mencatat permintaan dan baris ke-2 untuk mencatat respons.
sumber
Asumsi
RestTemplate
yang dikonfigurasi untuk menggunakan HttpClient 4.x, Anda dapat membaca tentang dokumentasi logging HttpClient ini di sini . Para penebang berbeda dari yang ditentukan dalam jawaban lainnya.Konfigurasi logging untuk HttpClient 3.x tersedia di sini .
sumber
Begitu banyak respons di sini yang membutuhkan perubahan koding dan kelas khusus dan itu benar-benar tidak perlu. Gte proxy debugging seperti fiddler dan atur lingkungan java Anda untuk menggunakan proxy pada baris perintah (-Dhttp.proxyHost dan -Dhttp.proxyPort) kemudian jalankan fiddler dan Anda dapat melihat permintaan dan respons secara keseluruhan. Juga hadir dengan banyak keuntungan tambahan seperti kemampuan untuk mengotak-atik hasil dan tanggapan sebelum dan setelah mereka dikirim untuk menjalankan percobaan sebelum melakukan modifikasi server.
Bit terakhir dari masalah yang dapat muncul adalah jika Anda harus menggunakan HTTPS, Anda harus mengekspor sertifikat SSL dari fiddler dan mengimpornya ke petunjuk java keystore (cacerts): kata sandi java keystore default biasanya "changeit".
sumber
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888
.Untuk masuk ke Logback dengan bantuan dari Apache HttpClient:
Anda membutuhkan Apache HttpClient di classpath:
Konfigurasikan Anda
RestTemplate
untuk menggunakan HttpClient:Untuk mencatat permintaan dan tanggapan, tambahkan ke file konfigurasi Logback:
Atau untuk lebih masuk:
sumber
org.apache.http.wire=DEBUG
Andaapplication.properties
sekarangTrik mengonfigurasi Anda
RestTemplate
dengan aBufferingClientHttpRequestFactory
tidak berfungsi jika Anda menggunakan apa punClientHttpRequestInterceptor
, yang akan Anda lakukan jika Anda mencoba masuk melalui pencegat. Ini karena cara yangInterceptingHttpAccessor
(yangRestTemplate
subclass) bekerja.Singkat cerita ... cukup gunakan kelas ini sebagai pengganti
RestTemplate
(perhatikan ini menggunakan API logging SLF4J, edit seperlunya):Saya setuju itu konyol bahwa ini membutuhkan banyak pekerjaan hanya untuk melakukan ini.
sumber
Menambahkan ke diskusi di atas ini hanya merupakan skenario Selamat. mungkin Anda tidak akan dapat mencatat respons jika terjadi kesalahan .
Dalam hal ini ditambah semua kasus di atas Anda harus menimpa DefaultResponseErrorHandler dan mengaturnya seperti di bawah ini
sumber
Anehnya, tidak ada solusi yang berfungsi karena RestTemplate tampaknya tidak mengembalikan respons pada beberapa kesalahan 500x klien dan server. Dalam hal ini, Anda harus mencatatnya juga dengan menerapkan ResponseErrorHandler sebagai berikut. Berikut adalah konsep kode, tetapi Anda mendapatkan intinya:
Anda dapat mengatur interseptor yang sama dengan penangan kesalahan:
Dan intersep mengimplementasikan kedua antarmuka:
sumber
Seperti @MilacH tunjukkan, ada kesalahan dalam implementasi. Jika statusCode> 400 dikembalikan, IOException dilemparkan, karena errorHandler tidak dipanggil, dari interseptor. Pengecualian dapat diabaikan dan kemudian ditangkap lagi dalam metode handler.
sumber
Solusi terbaik sekarang, tambahkan saja ketergantungan:
Ini berisi kelas LoggingRequestInterceptor yang bisa Anda tambahkan ke RestTemplate Anda:
mengintegrasikan utilitas ini dengan menambahkannya sebagai pencegat ke pegas RestTemplate, dengan cara berikut:
dan tambahkan implementasi slf4j ke kerangka kerja Anda seperti log4j.
atau langsung menggunakan "Zg2proRestTemplate" . "Jawaban terbaik" oleh @PaulSabou tampak begitu, karena httpclient dan semua lib apache.http tidak selalu dimuat saat menggunakan spring RestTemplate.
sumber
log("Headers: {}", request.headers)
masukLoggingRequestInterceptor:traceRequest
danlog("Headers: {}", response.headers)
masukLoggingRequestInterceptor:logResponse
. Anda mungkin ingin berpikir tentang menambahkan beberapa flag untuk mencatat header dan badan. Juga - Anda mungkin ingin memeriksa jenis konten tubuh untuk logging (misalnya aplikasi log saja / json *). Ini juga harus dapat dikonfigurasi. semua dalam semua, dengan tweak kecil Anda akan memiliki perpustakaan yang bagus untuk menyebar. kerja bagus :)Ingin menambahkan implementasi saya ini juga. Saya minta maaf untuk semua semi-titik dua yang hilang, ini ditulis dalam Groovy.
Saya membutuhkan sesuatu yang lebih dapat dikonfigurasi daripada jawaban yang diterima. Inilah kacang templat sisa yang sangat gesit dan akan mencatat semuanya seperti yang dicari OP.
Kelas Interceptor Penebangan Kustom:
Definisi Bean Templat Tempel:
Penerapan:
sumber
Rujuk Q / A untuk mencatat permintaan dan respons untuk templat sisanya dengan mengaktifkan beberapa bacaan di HttpInputStream
Mengapa ClientHttpRequestInterceptor kustom saya dengan respons kosong
sumber
org.apache.http.wire memberikan log yang terlalu tidak dapat dibaca, jadi saya menggunakan logbook untuk mencatat aplikasi Servlet dan RestTemplate req / resp untuk login
build.gradle
properti aplikasi
RestTemplate
sumber
Terkait dengan respons menggunakan ClientHttpInterceptor, saya menemukan cara untuk menjaga seluruh tanggapan tanpa Buffering pabrik. Cukup simpan aliran input tubuh respons di dalam byte array menggunakan beberapa metode utils yang akan menyalin array itu dari tubuh, tetapi penting, kelilingi metode ini dengan try catch karena akan pecah jika respons kosong (itu adalah penyebab Resource Access Exception) dan di tangkapan hanya membuat array byte kosong, dan dari sekadar membuat kelas dalam anonim dari ClientHttpResponse menggunakan array itu dan parameter lain dari respons asli. Daripada Anda dapat mengembalikan objek ClientHttpResponse baru ke rantai eksekusi templat sisanya dan Anda dapat mencatat respons menggunakan array byte tubuh yang sebelumnya disimpan. Dengan begitu Anda akan menghindari mengkonsumsi InputStream dalam respons aktual dan Anda dapat menggunakan respons Rest Template apa adanya. Catatan,
sumber
konfigurasi logger saya menggunakan xml
maka Anda akan mendapatkan sesuatu seperti di bawah ini:
melalui HttpMessageConverterExtractor.java:92, Anda perlu melanjutkan debug, dan dalam kasus saya, saya dapat ini:
dan ini:
outputMessage.getBody () berisi pesan yang dikirim http (tipe posting)
sumber