Menggunakan Spring ResponseEntity untuk Memanipulasi Respons HTTP

1. Pengenalan

Dengan menggunakan Spring, biasanya kita mempunyai banyak cara untuk mencapai tujuan yang sama, termasuk menyempurnakan respons HTTP.

Dalam tutorial ringkas ini, kita akan melihat cara menetapkan isi, status, dan tajuk respons HTTP menggunakan ResponseEntity .

2. ResponseEntity

ResponseEntity mewakili keseluruhan respons HTTP: kod status, tajuk dan isi . Hasilnya, kita dapat menggunakannya untuk mengkonfigurasi respons HTTP sepenuhnya.

Sekiranya kita mahu menggunakannya, kita mesti mengembalikannya dari titik akhir; Spring menjaga yang lain.

ResponseEntity adalah jenis generik. Oleh itu, kita boleh menggunakan jenis apa saja sebagai badan tindak balas:

@GetMapping("/hello") ResponseEntity hello() { return new ResponseEntity("Hello World!", HttpStatus.OK); }

Oleh kerana kami menentukan status respons secara terprogram, kami dapat kembali dengan kod status yang berbeza untuk senario yang berbeza:

@GetMapping("/age") ResponseEntity age( @RequestParam("yearOfBirth") int yearOfBirth) { if (isInFuture(yearOfBirth)) { return new ResponseEntity( "Year of birth cannot be in the future", HttpStatus.BAD_REQUEST); } return new ResponseEntity( "Your age is " + calculateAge(yearOfBirth), HttpStatus.OK); }

Selain itu, kami dapat menetapkan tajuk HTTP:

@GetMapping("/customHeader") ResponseEntity customHeader() { HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "foo"); return new ResponseEntity( "Custom header set", headers, HttpStatus.OK); }

Selanjutnya, ResponseEntity menyediakan dua antara muka pembangun bersarang : HeadersBuilder dan subinterfacenya, BodyBuilder . Oleh itu, kita dapat mengakses kemampuan mereka melalui kaedah statik ResponseEntity .

Kes yang paling mudah adalah respons dengan kod tindak balas badan dan HTTP 200:

@GetMapping("/hello") ResponseEntity hello() { return ResponseEntity.ok("Hello World!"); }

Untuk kod status HTTP yang paling popular, kami mendapat kaedah statik:

BodyBuilder accepted(); BodyBuilder badRequest(); BodyBuilder created(java.net.URI location); HeadersBuilder noContent(); HeadersBuilder notFound(); BodyBuilder ok();

Selain itu, kita dapat menggunakan kaedah status BodyBuilder (status HttpStatus) dan status BodyBuilder (status int) untuk menetapkan status HTTP.

Akhirnya, dengan ResponseEntity BodyBuilder.body (T body) kita dapat menetapkan badan respons HTTP:

@GetMapping("/age") ResponseEntity age(@RequestParam("yearOfBirth") int yearOfBirth) { if (isInFuture(yearOfBirth)) { return ResponseEntity.badRequest() .body("Year of birth cannot be in the future"); } return ResponseEntity.status(HttpStatus.OK) .body("Your age is " + calculateAge(yearOfBirth)); }

Kami juga boleh menetapkan tajuk khas:

@GetMapping("/customHeader") ResponseEntity customHeader() { return ResponseEntity.ok() .header("Custom-Header", "foo") .body("Custom header set"); }

Oleh kerana BodyBuilder.body () mengembalikan ResponseEntity dan bukannya BodyBuilder, ia harus menjadi panggilan terakhir.

Perhatikan bahawa dengan HeaderBuilder kami tidak dapat menetapkan sifat badan respons.

Ketika pulang ResponseEntity objek dari pengawal, kita mungkin mendapat pengecualian atau ralat semasa memproses permintaan itu dan ingin kembali maklumat ralat berkaitan kepada pengguna yang diwakili sebagai beberapa jenis lain, katakan E .

Spring 3.2 memberikan sokongan untuk @ExceptionHandler global dengan anotasi @ControllerAdvice baru , yang menangani senario seperti ini. Untuk perincian mendalam, rujuk artikel kami yang ada di sini.

Walaupun ResponseEntity sangat kuat, kita tidak boleh menggunakannya secara berlebihan. Dalam kes mudah, ada pilihan lain yang memenuhi keperluan kita dan menghasilkan kod yang lebih bersih.

3. Alternatif

3.1. @ResponseBody

Dalam aplikasi Spring MVC klasik, titik akhir biasanya mengembalikan halaman HTML yang diberikan. Kadang kala kita hanya perlu mengembalikan data sebenar; sebagai contoh, apabila kita menggunakan titik akhir dengan AJAX.

Dalam kes seperti itu, kita dapat menandai kaedah pengendali permintaan dengan @ResponseBody , dan Spring memperlakukan nilai hasil kaedah tersebut sebagai badan respons HTTP itu sendiri.

Untuk maklumat lebih lanjut, artikel ini adalah tempat yang baik untuk bermula.

3.2. @ResponseStatus

Apabila titik akhir kembali berjaya, Spring memberikan respons HTTP 200 (OK). Sekiranya titik akhir melontarkan pengecualian, Spring mencari pengendali pengecualian yang memberitahu status HTTP mana yang akan digunakan.

Kami dapat menandakan kaedah ini dengan @ResponseStatus, dan oleh itu, Spring kembali dengan status HTTP tersuai .

Untuk lebih banyak contoh, sila kunjungi artikel kami mengenai kod status tersuai.

3.3. Memanipulasi Tindak Balas Secara Langsung

Spring juga membolehkan kita mengakses objek javax.servlet.http.HttpServletResponse secara langsung; kita hanya perlu menyatakannya sebagai argumen kaedah:

@GetMapping("/manual") void manual(HttpServletResponse response) throws IOException { response.setHeader("Custom-Header", "foo"); response.setStatus(200); response.getWriter().println("Hello World!"); }

Oleh kerana Spring memberikan abstraksi dan keupayaan tambahan di atas pelaksanaan yang mendasari, kita seharusnya tidak memanipulasi tindak balas dengan cara ini .

4. Kesimpulan

Dalam artikel ini, kami membincangkan pelbagai cara untuk memanipulasi respons HTTP pada musim bunga, dan meneliti kelebihan dan kekurangannya.

Seperti biasa, contohnya terdapat di GitHub.