HTTP协议学习笔记

分类专栏:
学习总结

文章标签:
Java
计算机网络
原创

前言

因JavaEE课程作业要求写一篇关于HTTP的学习笔记,故有此文,正好借此机会整理一下HTTP的相关知识和我的思考理解。


一、为什么需要HTTP协议?

在网络中传输的信息一般都是二进制流,如何让我们发的信息可以被对方正确解析呢?如果没有一种标准来规范,这将会造成信息障碍,就像如果没有一种统一的文字,不同语言的人沟通便成了很大的障碍。 所以我们需要一种标准来规范计算机之间的信息交互,而HTTP协议便是互联网发展过程中流行起来的协议之一。

二、什么是HTTP协议?

1.HTTP简介

HTTP全称HyperText Transfer Protocol,便是我们常说的超文本传输协议。是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。

2.HTTP原理

HTTP是建立在传输层中的TCP上的一种协议,即在连接之前需要进行TCP的三次握手。目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样建立的 TCP 连接,就可以在多次请求中复用。

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

三、一个HTTP请求的历程

HTTP1.1

以下以访问http://www.163.com/index.html为例

1.HTTP 请求的准备

浏览器会将 www.163.com 这个域名发送给 DNS 服务器,让它解析为 IP 地址。然后传输层通过TCP三次握手建立连接。

2.HTTP 请求的构建

建立了连接以后,浏览器就要发送 HTTP 的请求。

请求的格式就像这样。 在这里插入图片描述

HTTP 的报文大概分为三大部分。第一部分是请求行,第二部分是请求的首部,第三部分才是请求的正文实体。

3.HTTP 请求的发送

HTTP 协议是基于 TCP 协议的,所以它使用面向连接的方式发送请求,通过 stream 二进制流的方式传给对方。当然,到了 TCP 层,它会把二进制流变成一个个报文段发送给服务器。在发送给每个报文段的时候,都需要对方有一个回应 ACK,来保证报文可靠地到达了对方。如果没有回应,那么 TCP 这一层会进行重新传输,直到可以到达。同一个包有可能被传了好多次,但是 HTTP 这一层不需要知道这一点,因为是 TCP 这一层在埋头苦干。

4.对方收到请求,进行处理

对方收到该请求,根据其端口交给相应程序进行处理,处理完毕后返回相应应答。

5.HTTP 应答的构建

HTTP 的返回报文也是有一定格式的。这也是基于 HTTP 1.1 的。 在这里插入图片描述

状态码会反映 HTTP 请求的结果。“200”意味着大吉大利;而我们最不想见的,就是“404”,也就是“服务端无法响应这个请求”。然后,短语会大概说一下原因。

接下来是返回首部的 key value。

这里面,Retry-After 表示,告诉客户端应该在多长时间以后再次尝试一下。“503 错误”是说“服务暂时不再和这个值配合使用”。

在返回的头部里面也会有 Content-Type,表示返回的是 HTML,还是 JSON。

6.发送应答

构造好了返回的 HTTP 报文,接下来就是把这个报文发送出去。还是交给 Socket 去发送,还是交给 TCP 层,让 TCP 层将返回的 HTML,也分成一个个小的段,并且保证每个段都可靠到达。

这些段加上 TCP 头后会交给 IP 层,然后把刚才的发送过程反向走一遍。虽然两次不一定走相同的路径,但是逻辑过程是一样的,一直到达客户端。客户端发现 MAC 地址符合、IP 地址符合,于是就会交给 TCP 层。

根据序列号看是不是自己要的报文段,如果是,则会根据 TCP 头中的端口号,发给相应的进程。这个进程就是浏览器,浏览器作为客户端也在监听某个端口。当浏览器拿到了 HTTP 的报文。

发现返回“200”,一切正常,于是就从正文中将 HTML 拿出来。HTML 是一个标准的网页格式。浏览器只要根据这个格式,展示出一个绚丽多彩的网页。这就是一个正常的 HTTP 请求和返回的完整过程。

HTTP2.0

当然 HTTP 协议也在不断的进化过程中,在 HTTP1.1 基础上便有了 HTTP 2.0。

HTTP 1.1 在应用层以纯文本的形式进行通信。每次通信都要带完整的 HTTP 的头,而且不考虑 pipeline 模式的话,每次的过程总是像上面描述的那样一去一回。这样在实时性、并发性上都存在问题。

为了解决这些问题,HTTP 2.0 会对 HTTP 的头进行一定的压缩,将原来每次都要携带的大量 key value 在两端建立一个索引表,对相同的头只发送索引表中的索引。

另外,HTTP 2.0 协议将一个 TCP 的连接中,切分成多个流,每个流都有自己的 ID,而且流可以是客户端发往服务端,也可以是服务端发往客户端。它其实只是一个虚拟的通道。流是有优先级的。

HTTP 2.0 还将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。常见的帧有 Header 帧,用于传输 Header 内容,并且会开启一个新的流。再就是 Data 帧,用来传输正文实体。多个 Data 帧属于同一个流。

通过这两种机制,HTTP 2.0 的客户端可以将多个请求分到不同的流中,然后将请求内容拆成帧,进行二进制传输。这些帧可以打散乱序发送, 然后根据每个帧首部的流标识符重新组装,并且可以根据优先级,决定优先处理哪个流的数据。

我们来举一个例子。假设我们的一个页面要发送三个独立的请求,一个获取 css,一个获取 js,一个获取图片 jpg。如果使用 HTTP 1.1 就是串行的,但是如果使用 HTTP 2.0,就可以在一个连接里,客户端和服务端都可以同时发送多个请求或回应,而且不用按照顺序一对一对应。

在这里插入图片描述

HTTP 2.0 其实是将三个请求变成三个流,将数据分成帧,乱序发送到一个 TCP 连接中。 在这里插入图片描述

HTTP 2.0 成功解决了 HTTP 1.1 的队首阻塞问题,同时,也不需要通过 HTTP 1.x 的 pipeline 机制用多条 TCP 连接来实现并行请求与响应;减少了 TCP 连接数对服务器性能的影响,同时将页面的多个数据 css、js、 jpg 等通过一个数据链接进行传输,能够加快页面组件的传输速度。

四、HTTP协议的问题

HTTP 2.0 虽然大大增加了并发性,但还是有问题的。因为 HTTP 2.0 也是基于 TCP 协议的,TCP 协议在处理包时是有严格顺序的。当其中一个数据包遇到问题,TCP 连接需要等待这个包完成重传之后才能继续进行。虽然 HTTP 2.0 通过多个 stream,使得逻辑上一个 TCP 连接上的并行内容,进行多路数据的传输,然而这中间并没有关联的数据。一前一后,前面 stream 2 的帧没有收到,后面 stream 1 的帧也会因此阻塞。

注:也因此出现了特定的协议来解决这个问题,如Google 的 QUIC 协议

五、HTTP于Java后端开发

1.Cookie/Session

HTTP本身是一个无状态的连接协议,什么叫无状态呢? 就是你上个请求发过服务器了,当你再发送一个请求到同一个服务器时,服务器并不会记得你之前发送过请求。当服务器需要上次访问结果(状态)的时候,你必须把状态放在新的请求中发送,这将会极为麻烦。

为了支持客户端与服务器之间的交互,我们就需要通过不同的技术为交互存储状态,而这些不同的技术就是Cookie和Session了。

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。 在这里插入图片描述

上图便是浏览器中的cookie信息。

Session

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

如何确认请求对应的Session呢?一种常见的做法就是根据请求中的cookie来确定相应的Session,所以我们一般可以在cookie中看到类似JSESSIONID等字眼,因为JSESSIONID是默认情况下SessionId的名称。服务器可以根据这个SessionId确定相应的Session。 在这里插入图片描述

Session对应到Java后端编程中的则是javax.servlet.http.HttpSession类。在Servlet里通过request.getSession()方法获取该客户的Session。

注:关于Cookie和Session其实有很多内容,详情请看这篇理解Cookie和Session机制

2.Java对HTTP的封装——HttpServletRequest和HttpServletResponse

对于发送过来的HTTP请求,Java会把相关信息封装至HttpServletRequest类中,届时只需操作HttpServletRequest对象即可。 在这里插入图片描述

应答也是如此,所有信息操作都封装在HttpServletResponse中。

在这里插入图片描述

例如,在拦截器中操作请求和应答 在这里插入图片描述

总结

以上便是我对HTTP协议以及相关知识的学习总结,熟悉理解HTTP协议对于Java后端开发者来说是很有必要的。

注:很多知识并未详细展开,如有需要请自行搜索相关知识。 有些篇幅是摘自我认为比较好的文章,侵删。

参考文章:

1.极客时间趣谈网络协议中的第14讲 | HTTP协议:看个新闻原来这么麻烦

2.理解Cookie和Session机制

3.HTTP协议超级详解

  • 作者:金昊霖
  • 发表时间:2020-7-04
  • 版权声明:自由转载-非商用-非衍生-保留署名(创意共享3.0许可证)
  • 评论

    留言