HTTP协议
0.9版本
GET /index.html
1
服务端只能返回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.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强大的封装带给我们的便利性