HTTP server implementation with Netty¶
Implementing an HTTP server using [[Netty]] involves configuring an EventLoop group, setting up a ServerBootstrap, and defining a channel pipeline to handle HTTP-specific encoding and decoding.^[600-developer-big-data-netty-netty-01.md]
Core Components¶
EventLoop Groups¶
A standard Netty server implementation utilizes two EventLoopGroup instances.^[600-developer-big-data-netty-netty-01.md]
* Boss Group: Responsible for accepting incoming connections.
* Worker Group: Handles the traffic of accepted connections.
Both groups are typically instantiated using NioEventLoopGroup, which manages the IO operations and event processing.^[600-developer-big-data-netty-netty-01.md]
Channel Configuration¶
The server is configured using a ServerBootstrap helper class.^[600-developer-big-data-netty-netty-01.md] Key configuration steps include:
1. Group Assignment: Passing the boss and worker groups to the bootstrap.
2. Channel Type: Specifying NioServerSocketChannel.class as the channel implementation.
3. Handler Registration: Setting a childHandler to initialize the channel pipeline for each new connection.
Channel Initialization¶
The ChannelInitializer is used to configure the ChannelPipeline.^[600-developer-big-data-netty-netty-01.md] For an HTTP server, the pipeline typically requires:
1. HttpServerCodec: A combined codec that acts as both a decoder for requests and an encoder for responses.
2. Custom Handler: A user-defined handler, often extending SimpleChannelInboundHandler<HttpRequest>, to contain the business logic.
Request Handling Logic¶
The core logic for processing a request resides in the custom handler.^[600-developer-big-data-netty-netty-01.md]
- Read Request: Override
channelRead0to receive the incomingHttpRequest. - Construct Response: Create a
FullHttpResponseusingDefaultFullHttpResponse.- Set the HTTP version (e.g.,
HTTP_1_1) and status (e.g.,OK). - Populate the content, typically using
Unpooled.copiedBufferto wrap data like strings into aByteBuf.
- Set the HTTP version (e.g.,
- Set Headers: Define
Content-TypeandContent-Lengthheaders. - Send Response: Use
ctx.writeAndFlush(response)to send the data back to the client. - Close Channel: Close the connection after the response is sent.
Server Lifecycle¶
The server is started by binding to a specific port (e.g., 8080) via serverBootstrap.bind().sync(), which blocks until the server is active.^[600-developer-big-data-netty-netty-01.md] To keep the server running and handle graceful shutdown, the application typically waits on the closeFuture() of the channel and finally invokes shutdownGracefully() on both event loop groups.^[600-developer-big-data-netty-netty-01.md]
Code Example¶
The following example demonstrates the structure of a basic HTTP server in Netty:
public class Netty01_Server {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new [NioEventLoopGroup](<./nioeventloopgroup.md>)();
EventLoopGroup workerGroup = new [NioEventLoopGroup](<./nioeventloopgroup.md>)();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap
.group(bossGroup, workerGroup)
.channel([NioServerSocketChannel](<./nioserversocketchannel.md>).class)
.childHandler(new MyChannelInitializer());
[ChannelFuture](<./channelfuture.md>) [ChannelFuture](<./channelfuture.md>) = serverBootstrap.bind(8080).sync();
[ChannelFuture](<./channelfuture.md>).channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
class MyChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
[ChannelPipeline](<./channelpipeline.md>) pipeline = ch.pipeline();
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
pipeline.addLast("MySimpleChannelInboundHandler", new MySimpleChannelInboundHandler());
}
}
class MySimpleChannelInboundHandler extends SimpleChannelInboundHandler<HttpRequest> {
@Override
protected void channelRead0([ChannelHandlerContext](<./channelhandlercontext.md>) ctx, HttpRequest httpRequest)
throws Exception {
[ByteBuf](<./bytebuf.md>) content = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
FullHttpResponse response =
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
ctx.writeAndFlush(response);
ctx.channel().close();
}
}
Sources¶
^[600-developer-big-data-netty-netty-01.md]