HTTP协议
0.9版本
GET /index.html
服务端只能返回html格式,传输过程只能处理文字。
1.0版本
支持任何格式的内容,包括图像、视频、二进制等等
引入了POST命令、HEAD
命令
HEAD
命令 : 这个命令和 get 是有相似之处的 只返回头部信息,不会返回全部内容,速度较快,一般用来验证连接的有效性
增加了请求头、状态码,以及权限、缓存等
那么1.0 他的会是什么样子的呢?
请求
GET / HTTP/1.0
User-Agent:Mozilla/1.0
Accept: */*
响应格式
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Encoding: gzip
<html>
<body> hello world </body>
</html>
a、 Content-Type
服务端通知客户端,当前数据的格式
示例: text/html 、 image/png 、 application/pdf 、 video/mp4
前面是一级类型,后面是二级类型,用斜杠分隔; 还可以增加其他参数,如编码格式。
Content-Type: text/plain; charset=utf-8
b、Content-Encoding
表示数据压缩的方式,gzip、compress、deflate
对应客户端的字段为 Accept-Encoding,代表接收哪些压缩方式
c、缺点和问题
每个TCP连接只能发送一个请求,发送完毕连接关闭,使用成本很高,性能较差。
Connection: keep-alive - 非标准字段
1.1版本
在http1.0
推出后的半年 1.1版本也随之而来,
这个版本也一直沿用至今,当前我们大部分的http请求 都是用的 1.1 版本的
这里我们使用 postman 来请求一下 常用的搜索引擎 cn.bing.com
请求
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
响应
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.
- 持久连接,含义为默认不关闭tcp连接,可以被多个请求复用。大多时候,浏览器对同一个域名,允许同时建立6个连接。
- 管道机制,支持客户端发送多个请求,管理请求的顺序的。服务器还是按照接受请求的顺序,返回对应的响应结果。
- Content-Length, 用来区分数据包的重要字段
- 支持PUT、DELETE、PATCH等命令
缺点和问题
当部分请求耗时较长时,仍会阻塞后续请求的处理速度,这种现象叫做“队头阻塞”/“线头阻塞”。
2.0版本
解决队头阻塞的问题,使用的是多路复用的方式。
多路复用 不只是在 netty上有 他可以运用到很多地方
说了这么多 上代码来操作一下吧!!
我们的编写思路是这样的
- 编写初始化服务端
- 编写自定义初始化器 和 自定义处理器
- 启动postman 查看我们设置的 http 的响应结果
我们这里有三个类
- HttpServer 初始化服务端
- MyHttpHandler 自定义处理器
- MyHttpInitializer 自定义初始化
首先是 server
我们需要在初始化服务端的时候 设置主从线程模型(Netty中常用)
设置 启动参数 和阻塞队列的长度等设置
设置 初始化
public class HttpServer {
public static void main(String[] args) {
//可以自定义线程的数量
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 默认创建的线程数量 = CPU 处理器数量 *2
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler())
//当前连接被阻塞的时候,BACKLOG代表的事 阻塞队列的长度
.option(ChannelOption.SO_BACKLOG, 128)
//设置连接保持为活动状态
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new MyHttpInitializer());
try {
//设置为异步启动 异步 关闭
ChannelFuture future = serverBootstrap.bind(9988).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//netty的优雅关闭 指 等一切执行完毕之后 慢慢的关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
编写 初始化
继承ChannelInitializer泛型为Channel,用来进行设置出站解码器和入站编码器
使用 codec netty封装好的解码器,这样我们就不用每次定义 解码和编码
public class MyHttpInitializer extends ChannelInitializer<Channel> {
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
//先对应请求解码,后对响应解码
//pipeline.addLast("decoder", new HttpRequestDecoder());
//pipeline.addLast("encoder", new HttpRequestEncoder());
//当然每次我们都要解码编码很麻烦,netty也有为我们提供对应的解决方案,建议直接使用这个 不会出错
pipeline.addLast("codec", new HttpServerCodec());
//压缩数据
pipeline.addLast("compressor", new HttpContentCompressor());
//聚合完整的信息 参数代表可以处理的最大值 此时的是 512 kb
pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024));
pipeline.addLast(new MyHttpHandler());
}
}
有了初始化,我们还需要一个做事的 那就是 处理器 Handler
netty帮我们封装了返回完整http响应的类 DefaultFullHttpResponse
我们只需要在读取的时候 设置协议,状态码和响应信息,
配置响应头的类型和长度 就可以完成对请求的响应
/*
* 泛型需要设置为 FullHttpRequest
* 筛选 message 为此类型的消息才处理
* */
public class MyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
//DefaultFullHttpResponse 是一个默认的完整的http响应
DefaultFullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.wrappedBuffer("hello http netty demo".getBytes())
);
// 我们还需要设置响应头
// 设置请求 响应头字段 可以使用 HttpHeaderNmaes
// 设置字段时 可以使用
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();
}
}
启动结果
postman 差看到的请求响应 参数
可以看到我们设置的 http1.1 协议
类型 text/plain 长度 47
响应给客户端的 内容 hello http netty demo
小结
- 了解 http 各个版本的解决了什么问题,优缺点,优劣性
- 手动编写一个服务端的响应,用postman 查看响应头我们设置的内容
- 体验到 netty强大的封装带给我们的便利性