Saya mencoba menyiapkan server layanan REST skala besar. Kami menggunakan Spring Boot 1.2.1 Spring 4.1.5, dan Java 8. Pengontrol kami menerapkan @RestController dan anotasi @RequestMapping standar.
Masalah saya adalah bahwa Boot Musim Semi mengatur pengalihan default untuk pengecualian pengontrol ke /error
. Dari dokumen:
Spring Boot menyediakan pemetaan / kesalahan secara default yang menangani semua kesalahan dengan cara yang masuk akal, dan terdaftar sebagai halaman kesalahan 'global' dalam wadah servlet.
Berasal dari bertahun-tahun menulis aplikasi REST dengan Node.js, bagi saya, ini tidak masuk akal. Pengecualian apa pun yang dihasilkan oleh titik akhir layanan harus kembali dalam respons. Saya tidak mengerti mengapa Anda akan mengirim arahan ulang ke apa yang kemungkinan besar konsumen Angular atau JQuery SPA yang hanya mencari jawaban dan tidak dapat atau tidak akan mengambil tindakan apa pun pada arahan ulang.
Apa yang ingin saya lakukan adalah menyiapkan penangan kesalahan global yang dapat mengambil pengecualian - baik sengaja dilemparkan dari metode pemetaan permintaan atau dihasilkan secara otomatis oleh Spring (404 jika tidak ada metode penangan ditemukan untuk tanda tangan jalur permintaan), dan mengembalikan respons kesalahan berformat standar (400, 500, 503, 404) ke klien tanpa pengalihan MVC. Secara khusus, kita akan mengambil kesalahan, log ke NoSQL dengan UUID, lalu kembali ke klien kode kesalahan HTTP yang tepat dengan UUID dari entri log di tubuh JSON.
Dokumen sudah tidak jelas tentang cara melakukan ini. Sepertinya saya bahwa Anda harus membuat implementasi ErrorController Anda sendiri atau menggunakan ControllerAdvice dengan cara tertentu, tetapi semua contoh yang saya lihat masih menyertakan penerusan respons ke semacam pemetaan kesalahan, yang tidak membantu. Contoh lain menunjukkan bahwa Anda harus membuat daftar setiap jenis Pengecualian yang ingin Anda tangani alih-alih hanya mencantumkan "Mudah Dibuang" dan mendapatkan semuanya.
Adakah yang bisa memberi tahu saya apa yang saya lewatkan, atau mengarahkan saya ke arah yang benar tentang cara melakukan ini tanpa menyarankan rantai yang Node.js akan lebih mudah untuk ditangani?
sumber
Jawaban:
Jawaban baru (2016-04-20)
Menggunakan Spring Boot 1.3.1.RELEASE
Langkah Baru 1 - Mudah dan tidak terlalu mengganggu untuk menambahkan properti berikut ke aplikasi.properti:
Jika bekerja dengan Aplikasi RESTful penuh, sangat penting untuk menonaktifkan pemetaan otomatis sumber daya statis karena jika Anda menggunakan konfigurasi default Spring Boot untuk menangani sumber daya statis maka penangan sumber daya akan menangani permintaan (itu dipesan terakhir dan dipetakan ke / ** yang artinya menerima permintaan yang belum ditangani oleh penangan lain dalam aplikasi) sehingga servlet pengirim tidak mendapat kesempatan untuk melemparkan pengecualian.
Jawaban Baru (2015-12-04)
Menggunakan Spring Boot 1.2.7.RELEASE
Langkah Baru 1 - Saya menemukan cara yang tidak terlalu mengganggu untuk mengatur flag "throExceptionIfNoHandlerFound". Ganti kode penggantian DispatcherServlet di bawah ini (Langkah 1) dengan ini di kelas inisialisasi aplikasi Anda:
Dalam hal ini, kami menetapkan bendera pada DispatcherServlet yang ada, yang mempertahankan setiap konfigurasi otomatis oleh kerangka Boot Spring.
Satu hal lagi yang saya temukan - penjelasan @EnableWebMvc mematikan Spring Boot. Ya, anotasi itu memungkinkan hal-hal seperti bisa menangkap semua pengecualian controller seperti dijelaskan di bawah, tetapi juga membunuh BANYAK konfigurasi otomatis yang bermanfaat yang biasanya diberikan oleh Spring Boot. Gunakan anotasi itu dengan sangat hati-hati saat Anda menggunakan Spring Boot.
Jawaban asli:
Setelah banyak penelitian dan menindaklanjuti solusi yang diposting di sini (terima kasih atas bantuannya!) Dan tidak ada jumlah kecil runtime menelusuri ke kode Spring, saya akhirnya menemukan konfigurasi yang akan menangani semua Pengecualian (bukan Kesalahan, tetapi baca terus) termasuk 404-an.
Langkah 1 - beri tahu SpringBoot untuk berhenti menggunakan MVC untuk situasi "handler not found". Kami ingin Spring melempar pengecualian alih-alih kembali ke klien, pandangan dialihkan ke "/ kesalahan". Untuk melakukan ini, Anda harus memiliki entri di salah satu kelas konfigurasi Anda:
Kelemahan dari ini adalah bahwa ia menggantikan servlet pengirim standar. Ini belum menjadi masalah bagi kami, tanpa ada efek samping atau masalah eksekusi yang muncul. Jika Anda akan melakukan hal lain dengan servlet operator karena alasan lain, ini adalah tempat untuk melakukannya.
Langkah 2 - Sekarang boot spring akan mengeluarkan eksepsi ketika tidak ada handler yang ditemukan, eksepsi itu dapat ditangani dengan yang lain dalam handler eksepsi yang disatukan:
Perlu diingat bahwa saya pikir anotasi "@EnableWebMvc" penting di sini. Tampaknya tidak ada yang berhasil tanpa itu. Dan itu saja - aplikasi boot Spring Anda sekarang akan menangkap semua pengecualian, termasuk 404, di kelas handler di atas dan Anda dapat melakukannya dengan sesuka Anda.
Satu poin terakhir - sepertinya tidak ada cara untuk mendapatkan ini untuk menangkap kesalahan yang dilemparkan. Saya memiliki ide aneh untuk menggunakan aspek-aspek untuk menangkap kesalahan dan mengubahnya menjadi Pengecualian yang dapat ditangani oleh kode di atas, tetapi saya belum punya waktu untuk benar-benar mencoba mengimplementasikannya. Semoga ini bisa membantu seseorang.
Setiap komentar / koreksi / peningkatan akan dihargai.
sumber
@ExceptionHandler
metode apa pun yang dipanggil saat menempatkannya ke dalam@ControllerAdvice
kelas meskipun mereka berfungsi dengan baik jika ditempatkan di@RestController
kelas.@EnableWebMvc
ada di kelas@ControllerAdvice
dan@Configuration
(saya menguji setiap kombinasi). Adakah ide atau contoh kerja? // @Andy WilkinsonDengan Spring Boot 1.4+ ditambahkan kelas keren baru untuk penanganan pengecualian yang lebih mudah yang membantu menghilangkan kode boilerplate.
Yang baru
@RestControllerAdvice
disediakan untuk penanganan pengecualian, ini adalah kombinasi dari@ControllerAdvice
dan@ResponseBody
. Anda dapat menghapus@ResponseBody
pada@ExceptionHandler
metode saat menggunakan anotasi baru ini.yaitu
Untuk menangani 404 kesalahan menambahkan
@EnableWebMvc
anotasi dan yang berikut ke application.properties sudah cukup:spring.mvc.throw-exception-if-no-handler-found=true
Anda dapat menemukan dan bermain dengan sumber-sumber di sini:
https://github.com/magiccrafter/spring-boot-exception-handling
sumber
@RestControllerAdvice
tanpa konfigurasi tambahan. Apa yang kulewatkan di sini?Saya pikir
ResponseEntityExceptionHandler
memenuhi persyaratan Anda. Sepotong sampel kode untuk HTTP 400:Anda dapat memeriksa pos ini
sumber
HttpRequestMethodNotSupportedException
dan plugin tabung yang sama di beberapa layanan mikro, untuk beberapa tujuan bisnis kita perlu menanggapi nama alias layanan mikro dalam respons. apakah ada cara kita bisa mendapatkan nama layanan mikro / nama pengontrol yang mendasarinya? Saya tahuHandlerMethod
akan memberikan nama metode java dari mana pengecualian berasal. Tapi di sini, tidak ada metode yang menerima permintaan, makaHandlerMethod
tidak akan diinisialisasi. Jadi, apakah ada solusi untuk menyelesaikan ini?Meskipun ini adalah pertanyaan yang lebih tua, saya ingin membagikan pemikiran saya tentang ini. Saya harap, itu akan bermanfaat bagi sebagian dari Anda.
Saat ini saya sedang membangun REST API yang menggunakan Spring Boot 1.5.2.RELEASE dengan Spring Framework 4.3.7.RELEASE. Saya menggunakan pendekatan Java Config (sebagai lawan dari konfigurasi XML). Selain itu, proyek saya menggunakan mekanisme penanganan pengecualian global menggunakan
@RestControllerAdvice
anotasi (lihat nanti di bawah).Proyek saya memiliki persyaratan yang sama dengan Anda: Saya ingin API REST saya mengembalikan sebuah
HTTP 404 Not Found
dengan muatan JSON yang menyertainya dalam respons HTTP ke klien API ketika mencoba mengirim permintaan ke URL yang tidak ada. Dalam kasus saya, muatan JSON terlihat seperti ini (yang jelas berbeda dari default Spring Boot, btw.):Saya akhirnya membuatnya bekerja. Berikut adalah tugas utama yang perlu Anda lakukan secara singkat:
NoHandlerFoundException
dilemparkan jika klien API memanggil URL yang tidak ada metode penangannya (lihat Langkah 1 di bawah).ApiError
) yang berisi semua data yang harus dikembalikan ke klien API (lihat langkah 2).NoHandlerFoundException
dan mengembalikan pesan kesalahan yang tepat ke klien API (lihat langkah 3).Ok, sekarang ke detail:
Langkah 1: Konfigurasikan application.properties
Saya harus menambahkan dua pengaturan konfigurasi berikut ke file proyek
application.properties
:Ini memastikan,
NoHandlerFoundException
dilemparkan dalam kasus di mana klien mencoba mengakses URL yang tidak ada metode pengontrol yang dapat menangani permintaan.Langkah 2: Buat Kelas untuk Kesalahan API
Saya membuat kelas yang mirip dengan yang disarankan dalam artikel ini di blog Eugen Paraschiv. Kelas ini merupakan kesalahan API. Informasi ini dikirim ke klien di badan respons HTTP jika terjadi kesalahan.
Langkah 3: Membuat / Mengkonfigurasi Handler Pengecualian Global
Saya menggunakan kelas berikut untuk menangani pengecualian (untuk kesederhanaan, saya telah menghapus pernyataan impor, kode logging dan beberapa potongan kode lain yang tidak relevan):
Langkah 4: Tulis tes
Saya ingin memastikan, API selalu mengembalikan pesan kesalahan yang benar ke klien panggilan, bahkan dalam kasus kegagalan. Jadi, saya menulis tes seperti ini:
The
@ActiveProfiles("dev")
penjelasan dapat dibiarkan pergi. Saya menggunakannya hanya karena saya bekerja dengan profil yang berbeda. IniRegexMatcher
adalah pencocokan Hamcrest khusus yang saya gunakan untuk lebih baik menangani bidang cap waktu. Ini kodenya (saya temukan di sini ):Beberapa catatan selanjutnya dari pihak saya:
@EnableWebMvc
anotasi. Ini tidak perlu dalam kasus saya.sumber
Bagaimana dengan kode ini? Saya menggunakan pemetaan permintaan fallback untuk menangkap 404 kesalahan.
sumber
Secara default Spring Boot memberikan json dengan detail kesalahan.
Ini juga berfungsi untuk semua jenis kesalahan pemetaan permintaan. Lihat artikel ini http://www.jayway.com/2014/10/19/spring-boot-error-responses/
Jika Anda ingin membuat log ke NoSQL. Anda dapat membuat @ControllerAdvice tempat Anda akan mencatatnya dan kemudian melemparkan kembali pengecualian. Ada contoh dalam dokumentasi https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
sumber
@RestControllerAdvice adalah fitur baru dari Spring Framework 4.3 untuk menangani Pengecualian dengan RestfulApi dengan solusi yang saling terkait:
sumber
Untuk pengendali REST, saya akan merekomendasikan untuk menggunakan
Zalando Problem Spring Web
.https://github.com/zalando/problem-spring-web
Jika Spring Boot bertujuan untuk menanamkan beberapa konfigurasi otomatis, pustaka ini melakukan lebih banyak untuk penanganan pengecualian. Anda hanya perlu menambahkan ketergantungan:
Dan kemudian tentukan satu atau beberapa sifat saran untuk pengecualian Anda (atau gunakan yang disediakan secara default)
Kemudian Anda dapat menetapkan saran pengontrol untuk penanganan pengecualian sebagai:
sumber
Untuk orang yang ingin merespons sesuai dengan kode status http, Anda dapat menggunakan
ErrorController
caranya:Di
ResponseBean
sini adalah pojo kebiasaan saya untuk tanggapan.sumber
Solusi dengan
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
dan@EnableWebMvc @ControllerAdvice
berfungsi untuk saya dengan Spring Boot 1.3.1, sementara tidak berfungsi pada 1.2.7sumber