Netty series: easily build a server that supports Chinese

flydean
中文

Introduction

I have talked about so many articles about netty before. They all talked about the underlying principles and implementation of netty. Everyone must be thinking about it. After reading so many articles, what can netty do? Today, let us use netty to simply build a server that supports Chinese and show the power of netty.

netty's HTTP support

The server we set up today is a server that supports HTTP1.1. Setting up a server in netty is like building a house, and finding the right tools can get twice the result with half the effort. So what kind of tools does netty provide to build an HTTP house?

Before explaining netty's support for HTTP, let's take a look at the development of HTTP version.

The full name of HTTP is Hypertext Transfer Protocol, which is a standard protocol that appeared after the development of the World Wide Web in 1989 and is used to transmit data on the WWW. HTTP/1.1 is a supplement and optimization based on the original HTTP protocol in 1997.

In 2015, in order to meet the needs of fast-transmitting web applications and modern browsers, a new HTTP/2 protocol has been developed, which is mainly optimized in mobile browsers, delay processing, image processing and video processing.

Basically all modern browsers support the HTTP/2 protocol, but there are still many applications that use the old HTTP/1.1 protocol. Netty provides different support packages for HTTP2 and HTTP1. The support package for HTTP1 is called netty-codec-http, and the package that supports HTTP2 is called netty-codec-http2.

This article will explain netty's support for HTTP1, and the introduction of HTTP2 will be continued in subsequent articles.

netty-codec-http provides some very useful packages for HTTP.

The first is the class HttpObject that represents the transmission object in HTTP. This class represents all objects in the transmission. There are two very important objects that inherit this class, namely HttpMessage and HttpContent.

HttpMessage may be different from what I imagined. It actually only contains two parts, HttpVersion and HttpHeaders, but it does not contain any content.

public interface HttpMessage extends HttpObject {

    HttpVersion protocolVersion();

    HttpMessage setProtocolVersion(HttpVersion version);

    HttpHeaders headers();
}

Here HttpVersion only supports HTTP/1.0 and HTTP/1.1 protocols. And HttpHeaders is the encapsulation of the header object in the HTTP request.

The subclasses of HttpMessage are HttpRequest and HttpResponse, so these two classes do not carry request content.

The content of the specific request is in HttpContent. HttpContent inherits from ByteBufHolder, which means that it can carry ByteBuf content information.

The real implementation classes of HttpContent are DefaultFullHttpRequest and DefaultFullHttpResponse, which contain HTTP headers and HTTP request response content information.

So the question is, why separate the HTTP header from the HTTP content?

This involves the compression mechanism in message transmission in HTTP 1.1. In order to improve transmission efficiency, object messages are generally compressed during transmission. However, for HTTP 1.1, the content of the header cannot be compressed, only the content part can be compressed, so it needs to be treated differently.

The principle of using HTTP in netty

We know that the bottom layer of netty is to build a channel between the client and the server, and transmit ByteBuf messages through the channel. So how does netty support HTTP requests?

After the client sends an HTTP request to the server, the server needs to use a decoder to decode the received data into various HttpObject objects that can be used by the application, so that it can be parsed in the application.

netty provides HttpResponseEncoder and HttpRequestDecoder classes to encode and decode HTTP messages.

If you don't want to use the two classes separately for encoding and decoding, netty also provides the HttpServerCodec class for encoding and decoding.

This class contains two parts of work, HttpRequestDecoder and HttpResponseEncoder, which can be used for encoding and decoding at the same time.

100 (Continue) Status

There is a unique feature in HTTP called 100 (Continue) Status, which means that when the client is not sure whether the server will receive the request, it can send a request header and add a "100-continue" to this header. Field, but the request body is not sent yet. The request body will not be sent until the response from the server is received.

In order to handle this kind of request, netty provides an HttpServerExpectContinueHandler object to handle the 100 Status situation.

Of course, if your client does not have such a request, you can directly use HttpObjectAggregator to merge HttpMessage and HttpContent into FullHttpRequest or FullHttpResponse.

Build an HTTP server for netty

With the above work, we can use netty to build an http server. The most important point is to add the corresponding codec and custom handler in HttpRequestServerInitializer.

    public void initChannel(SocketChannel ch) {
        ChannelPipeline p = ch.pipeline();
        p.addLast(new HttpServerCodec());
        p.addLast(new HttpServerExpectContinueHandler());
        p.addLast(new HttpRequestServerHandler());
    }

In the custom handler, we need to implement a function, that is, when receiving the client's request, we need to return a welcome message to the client.

First convert the obtained HttpObject into an HttpRequest object, then construct a DefaultFullHttpResponse object based on the request object, then set the header of the response object, and finally write the object to the channel.

The corresponding key codes are as follows:

 private static final byte[] CONTENT = "欢迎来到www.flydean.com!".getBytes(StandardCharsets.UTF_8);

    public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg;

            boolean keepAlive = HttpUtil.isKeepAlive(req);
            FullHttpResponse response = new DefaultFullHttpResponse(req.protocolVersion(), OK,
                                                                    Unpooled.wrappedBuffer(CONTENT));
            response.headers()
//                    .set(CONTENT_TYPE, TEXT_PLAIN)
                    .set(CONTENT_TYPE, "text/plain;charset=utf-8")
                    .setInt(CONTENT_LENGTH, response.content().readableBytes());

            if (keepAlive) {
                if (!req.protocolVersion().isKeepAliveDefault()) {
                    //设置header connection=keep-alive
                    response.headers().set(CONNECTION, KEEP_ALIVE);
                }
            } else {
                // 如果keepAlive是false,则设置header connection=close
                response.headers().set(CONNECTION, CLOSE);
            }
            ChannelFuture f = ctx.write(response);
            if (!keepAlive) {
                f.addListener(ChannelFutureListener.CLOSE);
            }
        }
    }

In the above key code, CONTENT contains a Chinese character string, and we use getBytes to convert it into a UTF-8 encoded byte array. If you want the client to correctly recognize the UTF-8 encoding, you need to set the content type file in the response header as: "text/plain;charset=utf-8".

Finally, use the following code to start the server:

 // server配置
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.option(ChannelOption.SO_BACKLOG, 1024);
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new HttpRequestServerInitializer());

            Channel ch = b.bind(PORT).sync().channel();
            log.info("请打开你的浏览器,访问 http://127.0.0.1:8000/");
            ch.closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

Summarize

Now, use your browser to visit the server address you set up, you can get "Welcome to www.flydean.com!". At this point, a simple netty server is complete.

For the examples in this article, please refer to: learn-netty4

This article has been included in http://www.flydean.com/19-netty-http-client-request/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", know technology, know you better!

阅读 386

程序那些事
Spring,区块链,密码学,分布式,多线程等教程 欢迎关注我的公众号:程序那些事,更多精彩等着您!

欢迎访问我的个人网站:www.flydean.com

731 声望
407 粉丝
0 条评论
你知道吗?

欢迎访问我的个人网站:www.flydean.com

731 声望
407 粉丝
文章目录
宣传栏