Netty application: quickly understand the features of http versions and a small demo of HttpServer

HTTP protocol

Version 0.9

GET /index.html

The server can only return html format, and the transmission process can only process text.

Version 1.0

Support content in any format, including image, video, binary, etc

POST command and HEAD command are introduced

HEAD command: this command is similar to get. It only returns header information and does not return all contents. It is fast. It is generally used to verify the effectiveness of the connection

Request header, status code, permission, cache, etc. are added

So what will he look like in 1.0?

request

GET / HTTP/1.0
User-Agent:Mozilla/1.0
Accept: */*

Response format

HTTP/1.0 200 OK
Content-Type: text/plain
Content-Encoding: gzip


   hello world 

a, Content-Type

The server notifies the client of the current data format

Examples: text/html, image/png, application/pdf, video/mp4

The first level type is preceded by the second level type, separated by a slash; You can also add other parameters, such as encoding format.

Content-Type: text/plain; charset=utf-8

b,Content-Encoding

Indicates the method of data compression, gzip, compress, deflate

The field of the corresponding client is accept encoding, which represents the compression methods received

c. Shortcomings and problems

Each TCP connection can only send one request. After sending, the connection is closed. The use cost is very high and the performance is poor.

Connection: keep-alive   - Nonstandard field

Version 1.1

Half a year after the launch of HTTP 1.0, version 1.1 also followed,

This version has been used until now. At present, most of our http requests use version 1.1

Here we use postman to request the common search engine cn.bing.com

request

GET / HTTP/1.1
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: 2e1942a8-9e7c-4c89-87d7-a46c11205b8c
Host: cn.bing.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

response

HTTP/1.1 200 OK
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Content-Encoding: br
Vary: Accept-Encoding
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Set-Cookie: SUID=M; domain=.bing.com; expires=Sun, 21-Nov-2021 09:49:46 GMT; path=/; HttpOnly
Set-Cookie: MUID=015C0F598C4C6F831C8A1FAC8D066E50; domain=.bing.com; expires=Thu, 15-Dec-2022 09:49:46 GMT; path=/
Set-Cookie: MUIDB=015C0F598C4C6F831C8A1FAC8D066E50; expires=Thu, 15-Dec-2022 09:49:46 GMT; path=/; HttpOnly
Set-Cookie: _EDGE_S=F=1&SID=1793E6C6781468071F6CF633795E69AE; domain=.bing.com; path=/; HttpOnly
Set-Cookie: _EDGE_V=1; domain=.bing.com; expires=Thu, 15-Dec-2022 09:49:46 GMT; path=/; HttpOnly
Set-Cookie: SRCHD=AF=NOFORM; domain=.bing.com; expires=Mon, 20-Nov-2023 09:49:46 GMT; path=/
Set-Cookie: SRCHUID=V=2&GUID=A3776BC1B7E749699ADB5F7804C9FEE3&dmnchg=1; domain=.bing.com; expires=Mon, 20-Nov-2023 09:49:46 GMT; path=/
Set-Cookie: SRCHUSR=DOB=20211120; domain=.bing.com; expires=Mon, 20-Nov-2023 09:49:46 GMT; path=/
Set-Cookie: SRCHHPGUSR=SRCHLANG=zh-Hans; domain=.bing.com; expires=Mon, 20-Nov-2023 09:49:46 GMT; path=/
Set-Cookie: _SS=SID=1793E6C6781468071F6CF633795E69AE; domain=.bing.com; path=/
Set-Cookie: ULC=; domain=.bing.com; expires=Fri, 19-Nov-2021 09:49:46 GMT; path=/
Set-Cookie: _HPVN=CS=eyJQbiI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiUCJ9LCJTYyI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiSCJ9LCJReiI6eyJDbiI6MSwiU3QiOjAsIlFzIjowLCJQcm9kIjoiVCJ9LCJBcCI6dHJ1ZSwiTXV0ZSI6dHJ1ZSwiTGFkIjoiMjAyMS0xMS0yMFQwMDowMDowMFoiLCJJb3RkIjowLCJHd2IiOjAsIkRmdCI6bnVsbCwiTXZzIjowLCJGbHQiOjAsIkltcCI6MX0=; domain=.bing.com; expires=Mon, 20-Nov-2023 09:49:46 GMT; path=/
X-SNR-Routing: 1
X-Cache: CONFIG_NOCACHE
X-MSEdge-Ref: Ref A: C567D165BB114CD98893F50FEF5FAEE8 Ref B: BJ1EDGE0716 Ref C: 2021-11-20T09:49:46Z
Date: Sat, 20 Nov 2021 09:49:45 GMT
 
The console only showsresponse bodies smaller than 10 KB inline. To view the complete body, inspect it by clicking  Open.
  • Persistent connection means that the tcp connection is not closed by default and can be reused by multiple requests. Most of the time, the browser allows six connections to the same domain name at the same time.
  • The pipeline mechanism supports the client to send multiple requests and manage the order of requests. The server still returns the corresponding response results in the order of accepting requests.
  • Content length, which is used to distinguish the important fields of the packet
  • Support PUT, DELETE, PATCH and other commands

Shortcomings and problems

When some requests take a long time, the processing speed of subsequent requests will still be blocked. This phenomenon is called "queue head blocking" / "thread head blocking".

Version 2.0

Multiplexing is used to solve the problem of queue head blocking.

Multiplexing is not just on netty, it can be used in many places

Said so much on the code to operate it!!

Our writing idea is like this

  • Write initialization server
  • Writing custom initializers and custom processors
  • Start postman to view the response results of the http we set

We have three classes here

  • HttpServer initialization server
  • MyHttpHandler custom processor
  • MyHttpInitializer custom initialization

The first is the server

We need to set the master-slave thread model when initializing the server (commonly used in Netty) Set the startup parameters and the length of the blocking queue Set initialization

public class HttpServer {
    public static void main(String[] args) {
        //You can customize the number of threads
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // Number of threads created by default = number of CPU processors * 2
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler())
                //When the current connection is blocked, the BACKLOG represents the length of the event blocking queue
                .option(ChannelOption.SO_BACKLOG, 128)
                //Set the connection to remain active
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(new MyHttpInitializer());

        try {
        //Set to asynchronous start asynchronous close
            ChannelFuture future = serverBootstrap.bind(9988).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
       		//netty's graceful shutdown means that it is closed slowly after everything is executed
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

Write initialization

The generic type of the inherited ChannelInitializer is Channel, which is used to set the outbound decoder and inbound encoder codec netty is used to encapsulate the decoder, so that we don't have to define decoding and coding every time

public class MyHttpInitializer extends ChannelInitializer<Channel> {
    @Override
    protected void initChannel(Channel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        //First decode the corresponding request, and then decode the response
        //pipeline.addLast("decoder", new HttpRequestDecoder());
        //pipeline.addLast("encoder", new HttpRequestEncoder());

        //Of course, it is troublesome for us to decode and encode every time. netty also provides us with corresponding solutions. It is recommended to use this directly without error
        pipeline.addLast("codec", new HttpServerCodec());
        //compressed data 
        pipeline.addLast("compressor", new HttpContentCompressor());
        //The aggregate complete information parameter represents the maximum value that can be processed. At this time, 512 kb
        pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
        pipeline.addLast(new MyHttpHandler());
    }
}

With initialization, we also need a processor Handler

netty helps us encapsulate the class DefaultFullHttpResponse that returns a complete http response We only need to set the protocol, status code and response information when reading, The response to the request can be completed by configuring the type and length of the response header

/*
 * Generic needs to be set to FullHttpRequest
 * Filter messages to process messages of this type
 * */
public class MyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
        //DefaultFullHttpResponse is a default full http response
        DefaultFullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
                Unpooled.wrappedBuffer("hello http netty demo".getBytes())
        );
        //    We also need to set the response header
        // HttpHeaderNmaes can be used to set the request response header field
        // You can use the
        HttpHeaders headers = response.headers();
        headers.add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN + ";charset=UTF-8");
        headers.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
        ctx.write(response);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }
}

Start result

Request response parameters seen by postman You can see the http1.1 protocol we set up Type text/plain length 47 Content to respond to the client hello http netty demo

Summary

  1. Understand the problems, advantages, disadvantages and advantages of each version of http
  2. Manually write a server response, and use postman to view the content of the response header we set
  3. Experience the convenience brought by the powerful encapsulation of netty

Added by smixcer on Mon, 22 Nov 2021 06:37:57 +0200