Mapping-Anfragen für Netty

Es war einmal in einem weit, weit ... Projekt, ich musste die Verarbeitung von http-Anfragen auf Netty durchführen . Leider gab es in Netty keine praktischen Standardmechanismen für die Zuordnung von http-Anforderungen (und dieses Framework ist dafür überhaupt nicht geeignet). Daher wurde beschlossen, einen eigenen Mechanismus zu implementieren.


Wenn der Leser anfing, sich über das Schicksal des Projekts Sorgen zu machen, dann ist es das nicht wert, alles ist in Ordnung mit ihm, weil In Zukunft wurde beschlossen, den Webdienst in einem für RESTful-Dienste schärferen Rahmen umzuschreiben, ohne eigene Fahrräder zu verwenden. Aber die Erfolge sind geblieben und können für jemanden nützlich sein, deshalb möchte ich sie teilen.

Netty ist ein Framework für die Entwicklung leistungsstarker Netzwerkanwendungen. Weitere Informationen finden Sie auf der Projektwebsite.
Netty bietet sehr praktische Funktionen zum Erstellen von Socket-Servern, aber meiner Meinung nach ist diese Funktionalität zum Erstellen von REST-Servern nicht sehr praktisch.


Anforderungsverarbeitung mit der Standard-Netty-Engine


Um Anforderungen in Netty zu verarbeiten, müssen Sie von der ChannelInboundHandlerAdapter Klasse erben und die channelRead Methode überschreiben.


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

Um die für die Verarbeitung von http-Anforderungen erforderlichen Informationen zu erhalten, kann das msg Objekt in HttpRequest .


 HttpRequest request = (HttpRequest) msg; 

Danach können Sie alle Informationen aus dieser Anfrage erhalten. Zum Beispiel die URL der Anfrage.


 String uri = request.uri(); 

Art der Anfrage.


 HttpMethod httpMethod = request.method(); 

Und der Inhalt.


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

Der Inhalt kann beispielsweise json sein, das im Hauptteil der POST Anforderung übergeben wird. ByteBuf ist eine Klasse aus der Netty- Bibliothek, daher ist es unwahrscheinlich, dass JSON-Parser damit arbeiten, aber es kann sehr einfach in eine Zeichenfolge umgewandelt werden.


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

Das ist im Allgemeinen alles. Mit den oben genannten Methoden können Sie http-Anforderungen verarbeiten. Es stimmt, alles muss an einem Ort verarbeitet werden, nämlich in der channelRead Methode. Auch wenn wir die Logik der Verarbeitung von Anforderungen in verschiedene Methoden und Klassen unterteilen, müssen Sie die URL diesen Methoden irgendwo an einer Stelle zuordnen.


Mapping anfordern


Wie Sie sehen, ist es möglich, die Zuordnung von http-Anforderungen mithilfe der Standard- Netty- Funktionalität zu implementieren. Es ist wahr, es wird nicht sehr bequem sein. Ich möchte die Verarbeitung von http-Anfragen irgendwie vollständig durch verschiedene Methoden trennen (zum Beispiel wie im Frühjahr ). Mit Hilfe der Reflexion wurde versucht, einen ähnlichen Ansatz umzusetzen. Daraus ergab sich die num- Bibliothek. Den Quellcode finden Sie hier .
Um die Anforderungszuordnung mithilfe der num- Bibliothek zu verwenden, reicht es aus, von der AbstractHttpMappingHandler Klasse zu erben. Anschließend können Sie in dieser Klasse Anforderungshandlermethoden erstellen. Die Hauptanforderung für diese Methoden besteht darin, dass sie FullHttpResponse oder seine Nachkommen zurückgeben. Sie können mithilfe von Anmerkungen anzeigen, durch welche http-Anforderung diese Methode aufgerufen wird:


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

Der Anmerkungsname gibt an, welche Art von Anforderung aufgerufen wird. Es werden vier Arten von Anforderungen unterstützt: GET , POST , PUT und DELETE . Als Wertparameter in der Anmerkung müssen Sie die URL angeben. Beim Zugriff wird die gewünschte Methode aufgerufen.


Ein Beispiel dafür, wie der GET aussieht, der die Zeichenfolge 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 anfordern


Die Übergabe von Parametern aus der Anforderung an die Handler-Methode erfolgt ebenfalls mithilfe von Anmerkungen. Verwenden Sie dazu eine der folgenden Anmerkungen:


  • @PathParam
  • @QueryParam
  • @RequestBody

@PathParam


Zum @PathParam Annotation @PathParam . Wenn Sie es als Wertparameter der Anmerkung verwenden, müssen Sie den Parameternamen angeben. Darüber hinaus muss der Parametername auch in der Anforderungs-URL angegeben werden.


Ein Beispiel dafür, wie der GET , welcher Parameter für den id Pfad übergeben wird und welchen dieser Parameter zurückgibt.


 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


Zum @QueryParam Abfrageparametern wird die Annotation @QueryParam . Wenn Sie es als Wertparameter der Anmerkung verwenden, müssen Sie den Parameternamen angeben. Die Parameterbindung kann mit dem required Annotationsparameter gesteuert werden.


Ein Beispiel dafür, wie der GET aussehen wird, an das die Abfrageparameternachricht übergeben wird und der diesen Parameter zurückgibt.


 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


Um den Hauptteil der POST Anforderungen zu übertragen, wird die Annotation @RequestBody . Daher darf es nur in POST Anfragen verwendet werden. Es wird angenommen, dass Daten im JSON-Format als Anforderungshauptteil übertragen werden. Um @RequestBody verwenden zu @RequestBody muss daher die Implementierung der JsonParser Schnittstelle an den JsonParser werden, der Daten aus dem Anforderungshauptteil analysiert. Außerdem verfügt die Bibliothek bereits über eine Standardimplementierung von JsonParserDefault . Diese Implementierung verwendet jackson als Parser.


Ein Beispiel dafür, wie ein POST Anforderungshandler aussehen wird, in dem sich ein Anforderungshauptteil befindet.


 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)); } } 

Die Message lautet wie folgt.


 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; } } 

Fehlerbehandlung


Wenn während der Verarbeitung von Anforderungen eine Exception auftritt und diese nicht im Code der Handler-Methoden abgefangen wird, wird die Antwort mit dem 500. Code zurückgegeben. Um eine Logik für die Fehlerbehandlung zu schreiben, reicht es aus, die exceptionCaught Methode in der Handler-Klasse neu zu definieren.


 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)); } } 

Fazit


Das ist im Allgemeinen alles. Ich hoffe das war interessant und wird jemandem nützlich sein.




Hier finden Sie einen Beispielcode für den Netty http-Server, der die num- Bibliothek verwendet.

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


All Articles