Memetakan permintaan untuk Netty

Sekali waktu dalam satu jauh, jauh ... proyek, saya perlu melakukan pemrosesan permintaan http di Netty . Sayangnya, tidak ada mekanisme standar yang nyaman untuk memetakan permintaan http di Netty (dan kerangka kerja ini sama sekali tidak untuk itu), oleh karena itu, diputuskan untuk menerapkan mekanisme kami sendiri.


Jika pembaca mulai khawatir tentang nasib proyek, maka itu tidak layak, semuanya baik-baik saja dengannya, karena di masa depan, diputuskan untuk menulis ulang layanan web pada kerangka kerja yang lebih tajam untuk layanan tenang, tanpa menggunakan sepeda Anda sendiri. Tetapi pencapaian itu tetap ada, dan itu bisa bermanfaat bagi seseorang, jadi saya ingin membagikannya.

Netty adalah kerangka kerja untuk mengembangkan aplikasi jaringan berkinerja tinggi. Anda dapat membaca lebih lanjut tentang itu di situs web proyek.
Netty menyediakan fungsionalitas yang sangat nyaman untuk membuat server socket, tetapi menurut saya, fungsionalitas ini tidak terlalu nyaman untuk membuat server REST.


Meminta pemrosesan menggunakan mesin Netty standar


Untuk memproses permintaan di Netty, Anda perlu mewarisi dari kelas ChannelInboundHandlerAdapter dan mengganti metode channelRead .


 public class HttpMappingHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { } } 

Untuk mendapatkan informasi yang diperlukan untuk memproses permintaan http, objek msg dapat dilemparkan ke HttpRequest .


 HttpRequest request = (HttpRequest) msg; 

Setelah itu, Anda dapat memperoleh informasi apa pun dari permintaan ini. Misalnya, URL permintaan.


 String uri = request.uri(); 

Jenis permintaan.


 HttpMethod httpMethod = request.method(); 

Dan isinya.


 ByteBuf byteBuf = ((HttpContent) request).content(); 

Konten tersebut mungkin, misalnya, json diteruskan dalam isi permintaan POST . ByteBuf adalah kelas dari perpustakaan Netty , jadi parser json tidak mungkin bekerja dengannya, tetapi ia dapat dengan mudah dilemparkan ke string.


 String content = byteBuf.toString(StandardCharsets.UTF_8); 

Itu, secara umum, itu saja. Dengan menggunakan metode di atas, Anda dapat memproses permintaan http. Benar, semuanya harus diproses di satu tempat, yaitu dalam metode channelRead . Bahkan jika kami memisahkan logika pemrosesan permintaan ke berbagai metode dan kelas, Anda masih harus memetakan URL ke metode ini di satu tempat di satu tempat.


Meminta Pemetaan


Yah, seperti yang Anda lihat, adalah mungkin untuk mengimplementasikan pemetaan permintaan http menggunakan fungsionalitas Netty standar. Benar, itu tidak akan nyaman. Saya ingin memisahkan pemrosesan http-request dengan metode yang berbeda (misalnya, seperti yang dilakukan pada musim semi ). Dengan bantuan refleksi, upaya dilakukan untuk menerapkan pendekatan serupa. Perpustakaan num ternyata dari ini. Kode sumbernya dapat ditemukan di sini .
Untuk menggunakan pemetaan kueri menggunakan pustaka num , cukup mewarisi dari kelas AbstractHttpMappingHandler , setelah itu Anda bisa membuat metode penangan permintaan di kelas ini. Persyaratan utama untuk metode ini adalah mereka mengembalikan FullHttpResponse atau turunannya. Anda dapat menunjukkan dengan http apa permintaan metode ini akan dipanggil menggunakan anotasi:


  • @Get
  • @Post
  • @Put
  • @Delete

Nama anotasi menunjukkan jenis permintaan apa yang akan dipanggil. Empat jenis permintaan didukung: GET , POST , PUT dan DELETE . Sebagai parameter value dalam anotasi, Anda harus menentukan URL, ketika diakses, metode yang diinginkan akan dipanggil.


Contoh bagaimana penangan GET terlihat, yang mengembalikan string Hello, world! .


 public class HelloHttpHandler extends AbstractHttpMappingHandler { @Get("/test/get") public DefaultFullHttpResponse test() { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, OK, Unpooled.copiedBuffer("Hello, world!", StandardCharsets.UTF_8)); } } 

Parameter Permintaan


Melewati parameter dari permintaan ke metode handler juga dilakukan menggunakan anotasi. Untuk melakukan ini, gunakan salah satu anotasi berikut:


  • @PathParam
  • @QueryParam
  • @RequestBody

@PathParam


Untuk melewati parameter jalur, penjelasan @PathParam . Saat menggunakannya sebagai parameter nilai anotasi, Anda harus menentukan nama parameter. Selain itu, nama parameter juga harus ditentukan dalam URL permintaan.


Contoh bagaimana penangan GET akan melihat ke mana parameter jalur id dilewati dan parameter ini kembali.


 public class HelloHttpHandler extends AbstractHttpMappingHandler { @Get("/test/get/{id}") public DefaultFullHttpResponse test(@PathParam(value = "id") int id) { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, OK, Unpooled.copiedBuffer(id, StandardCharsets.UTF_8)); } } 

@QueryParam


Untuk melewati parameter kueri, penjelasan @QueryParam . Saat menggunakannya sebagai parameter nilai anotasi, Anda harus menentukan nama parameter. Penjilidan parameter dapat dikontrol menggunakan parameter anotasi yang required .


Contoh bagaimana penangan GET akan terlihat, ke mana message parameter kueri diteruskan dan yang mengembalikan parameter ini.


 public class HelloHttpHandler extends AbstractHttpMappingHandler { @Get("/test/get") public DefaultFullHttpResponse test(@QueryParam(value = "message") String message) { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, OK, Unpooled.copiedBuffer(message, StandardCharsets.UTF_8)); } } 

@RequestBody


Untuk mengirimkan isi permintaan POST , anotasi @RequestBody . Karena itu, hanya diperbolehkan menggunakannya dalam permintaan POST . Diasumsikan bahwa data format json akan dikirim sebagai badan permintaan. Oleh karena itu, untuk menggunakan @RequestBody perlu untuk meneruskan implementasi antarmuka JsonParser ke konstruktor kelas handler, yang akan terlibat dalam JsonParser parsing data dari badan permintaan. Juga, perpustakaan sudah memiliki implementasi standar JsonParserDefault . Implementasi ini menggunakan jackson sebagai parser.


Contoh bagaimana penangan permintaan POST akan terlihat di mana ada badan permintaan.


 public class HelloHttpHandler extends AbstractHttpMappingHandler { @Post("/test/post") public DefaultFullHttpResponse test(@RequestBody Message message) { return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, OK, Unpooled.copiedBuffer("{id: '" + message.getId() +"', msg: '" + message.getMessage() + "'}", StandardCharsets.UTF_8)); } } 

Kelas Message adalah sebagai berikut.


 public class Message { private int id; private String message; public Message() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 

Menangani kesalahan


Jika selama pemrosesan permintaan Exception terjadi dan tidak dicegat dalam kode metode penangan, maka jawaban dengan kode ke-500 akan dikembalikan. Untuk menulis beberapa logika untuk penanganan kesalahan, itu sudah cukup untuk mendefinisikan kembali metode exceptionCaught di kelas handler.


 public class HelloHttpHandler extends AbstractHttpMappingHandler { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { super.exceptionCaught(ctx, cause); ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)); } } 

Kesimpulan


Itu, secara umum, itu saja. Saya harap ini menarik dan akan bermanfaat bagi seseorang.




Kode contoh server Netty http menggunakan perpustakaan num tersedia di sini .

Source: https://habr.com/ru/post/id435864/


All Articles