开发实战
1. 使用echo服务器模拟http
通过上一篇文章中的echo服务器程序来模拟一次HTTP请求。
接收消息的代码如下:
public class ServerStringHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("服务端接收到消息:" + msg);
ctx.writeAndFlush(msg);
}
}
我们通过postman直接访问echo服务器:
请求成功,echo服务器接收到了本次HTTP请求,控制台打印内容如下:
服务端接收到消息:GET / HTTP/1.1
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: b340a7ba-bf85-48a7-97af-0bae5e94750e
Host: localhost:8001
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
上面的原理很容易理解,postman通过tcp建立与服务器localhost:8001的连接,然后自己组装了HTTP request消息,然后发送给echo服务器,echo服务器拿到完整的内容后将其打印在控制台,随后返回一条文本数据。
也正是echo服务器返回了一条文本数据,并未组装HTTP response消息,导致postman并未识别出服务器返回的内容。
这里简单提一下HTTP协议:
超文本传输协议(HyperText Transfer Protocol,HTTP)协议属于七(四)层协议中的应用层协议。HTTP协议其实是客户端和服务端之间请求和应答的标准,它规定了每次请求或返回的标准格式。基于HTTP对消息传输的顺序性和稳定性要求的前提下,HTTP协议一般使用TCP协议进行网络传输,路由寻址依旧是IP协议。
HTTP协议的消息格式
(HTTP Messages):
- Start line CRLF:request|response的起始栏
- n * (header CRLF):消息头,以key: value 形式组装,末尾跟上回车换行,最终构成的消息头
- CRLF:空行用于区分消息头和消息体。
- Body:消息体
了解完HTTP协议之后,我们通过如下格式构建HTTP Response消息:
- Start line格式:HTTP-Version SP Status-Code SP Reason-Phrase CRLF
- Response Header格式:KEY: VALUE CRLF
- CRLF
- Response Body格式:data
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("服务端接收到消息:" + msg);
String message = "HTTP/1.1 200 OK\n" +
"Content-Length: 35\n" +
"Date: " + new Date() + "\n" +
"Connection: keep-alive\n" +
"Content-Type: text/plain\n" +
"\n" +
"Reply, This is reply from server-.^";
System.out.println(message);
ctx.writeAndFlush(message);
}
重启后再次请求,postman成功识别出了我们拼接的结果:
通过上述的模拟实验,相信你已经大致理解了HTTP运作的流程。所以,我们要实现HTTP客户端,只需要自行拼凑出HTTP request内容;要实现HTTP服务端,只需要接收和解析request,并根据结果返回response即可。
听起来很简单,但是如果我们要自己来实现HTTP通信,处理各种请求头、cookie、消息体以及压缩算法等等,那么这份工作量过于巨大,所幸netty提供了完整的HTTP协议请求和接收的封装处理。通过使用netty-codec-http
包中的内容,我们就可以轻松的进行HTTP解析和处理工作。
<!-- netty-all包含以下两个依赖 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<!-- 处理HTTP的请求、返回的消息发送和接收 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
</dependency>
<!-- 处理HTTP/2框架下的消息发送和接收 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
</dependency>
2. netty http核心类
为了更好的理解netty处理HTTP收发的机制,我们有必要先了解
netty-codec-http
包中的HTTP核心类。
HTTP消息相关类:
- HttpObject:HTTP对象,是HTTP消息的顶层接口。
- HttpMessage:HTTP消息的接口定义,提供HttpRequest和HttpResponse的共用属性,如协议版本
HttpVersion
和请求头HttpHeaders
,默认实现类DefaultHttpMessage
。 - HttpContent:HTTP消息体,用于存储body内容,默认实现类
DefaultHttpContent
。在进行大文件传输或消息头参数有Transfer-Encoding:chunked
时使用,消息体将会进行