在浏览器输入一行url发生了什么 ?

220 阅读8分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

HTTP的本质

HTTP协议是浏览器与服务器之间的数据传送协议,作为应用层协议,HTTP是给予TCP/IP协议来传递数据的额(HTML文件、图片、查询结果等),HTTP协议不涉及数据包(Packet)传输,主要规定了客户端和服务器之间的通信格式 。举个例子:假如浏览器需要从远程HTTP服务器获取一个HTML文本,在这个过程中,浏览器实际上要做两件事。

  • 与服务器建立Socket连接。
  • 生成请求数据并通过Socket发送出去。

第一步比较容易理解,浏览器从地址栏获取用户输入的网址和端口,去连接远端的服务器,这样就能通信了。

我们重点来看第二步,这个请求数据到底长成什么样呢?都请求些什么内容呢?或者换句话说,浏览器需要告诉服务端什么信息呢 ?

首先最基本的是,你要让服务端知道你的意图,你是想获取内容还是提交内容;其次你需要告诉服务端你想要哪个内容。那么要把这些信息以一种什么样的格式放到请求里去呢?这就是HTTP协议要解决的问题。也就是说,HTTP协议的本质就是一种浏览器和服务器之间约定好的通信格式。那浏览器与服务器之间具体怎么工作的呢?

HTTP工作原理

请你来看下面这张图,我们过一遍一次HTTP的请求过程。

图先欠着 。。。。。。。

从图上可以看到,这个过程是:

  1. 用户通过浏览器进行了一个操作,比如输入网址并且回车,或者是点击链接,接着浏览器获取了这个事件。
  2. 浏览器向服务端发出TCP连接请求
  3. 服务程序接受浏览器的连接请求,并经过TCP的三次握手建立连接。
  4. 浏览器将请求数据打包成一个HTTP协议的数据包。
  5. 浏览器将该数据包推入网络,数据包经过网络传输,最终到达服务端程序。
  6. 服务端程序拿到这个数据包后,同样以HTTP协议格式解包,获取到客户端的意图。
  7. 得知客户端意图后进行处理,比如提供静态文件或者调用服务端程序获得动态结果。
  8. 服务器将响应结果(可能是HTML或者图片等)按照HTTP协议格式打包。
  9. 服务器将响应数据包推入网络,数据包经过网络传输最终到达浏览器。
  10. 浏览器拿到数据包后,以HTTP协议的格式解包,然后解析数据,假设这里的数据是HTML。
  11. 浏览器将HTML文件展示在页面上。

那我们想要探究的Tomcat和Jetty作为一个HTTP服务器,在这个过程中都做了些什么事情呢?主要是接受连接、解析请求数据、处理请求和发送响应这几个步骤。这里请你注意,可能有成千上万的浏览器同时请求同一个HTTP服务器,因此Tomcat和Jetty为了提高服务能力和并发度,往往会将自己要做的几个事情并行化,具体来说就是使用多线程的技术。

HTTP请求响应实例

你有没有注意到,在浏览器和HTTP服务器之间通信的过程中,首先要将数据打包成HTTP协议的格式,那HTTP协议的数据包具体长什么样呢? 

HTTP请求数据由三部分组成,分别是请求行、请求报头、请求正文 。当这个HTTP请求数据到达Tomcat后,Tomcat会把HTTP请求数据字节流解析成一个Request对象,这个Request对象封装了HTTP所有的请求信息。接着Tomcat把这个Request对象交给Web应用去处理,处理完后得到一个Response对象,Tomcat会把这个Response对象转成HTTP格式的响应数据并发送给浏览器。

HTTP响应的格式,HTTP的响应也是由三部分组成,分别是状态行、响应报头、报文主体。

Cookie和Session

我们知道,HTTP协议有个特点是无状态,请求与请求之间是没有关系的。这样会出现一个很尴尬的问题:Web应用不知道你是谁。比如你登录淘宝后,在购物车中添加 三件商品,刷新一下网页,这是系统提示仍处于未登录的状态,购物车也清空了,很显然这种情况是不可接受呢。因此HTTP协议需要一种技术让请求与请求之间建立起联系,并且服务器需要知道这个请求来自哪个用户,于是Cookie技术出现了。

Cookie是HTTP报文的一个请求头,Web应用可以将用户的标识信息或者其他一些信息(用户名等)储存在Cookie中。用户经过验证之后,每次HTTP请求报文中都包含Cookie,这样服务器读取这个Cookie请求头就知道用户是谁了。Cookie本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息。

由于Cookie以明文的方式储存在本地,而Cookie中往往带有用户信息,这样就造成了非常大的安全隐患。而Session的出现解决了这个问题,Session可以理解为服务器端开辟的存储空间,里面保存了用户的状态,用户信息以Session的形式存储在服务端。当用户请求到来时,服务端可以把用户的请求和用户的Session对应起来。那么Session是怎么和请求对应起来的呢?答案是通过Cookie,浏览器在Cookie中填充了一个SessionID之类的字段用来标识请求。

具体工作过程是这样的:服务器在创建Session的同时,会为该Session生成唯一的SessionID,当浏览器再次发送请求的时候,会将这个SessionID带上,服务器接收到请求之后就会依据SessionID找到相应的Session,找到Session后,就可以在Session中获取或者添加内容了。而这些内容只会保存在服务器中,发送到客户端只有SessionID,这样相对安全,也节省了网络流量,因为不需要在Cookie中存储大量用户信息。

Session创建与存储

那么Session在何时何地创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同的创建的Session的方法。在Java中,是Web应用程序在调用HttpServletRequest的getSession方法时,由Web容器(比如Tomcat)创建的。

Tomcat的Session管理器提供了多种持久化方案来存储Session,通常会采用高性能的存储方式,比如Redis,并且通过集群部署的方式,防止单点故障,从而提升高可用。同时,Session有过期时间,因此Tomcat会开启后台线程定期的轮询,如果Session过期了就将Session失效。

本期精华

HTTP协议和其他应用层协议一样,本质上是一种通信格式。回到文章开头我问你的问题,其实答案很简单:HTTP是通信的方式,HTML才是通信的目的,就好比HTTP是信封,信封里面的信才是内容;但是没有信封,信也没办法寄出去。HTTP协议就是浏览器与服务器之间的沟通语言,具体交互过程是请求、处理和响应。

由于HTTP是无状态的协议,为了识别请求是哪个用户发过来的,出现了Cookie和Session技术。Cookie本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息;Session可以理解为服务器开辟的存储空间,里面保存的信息用于保持状态。作为Web容器,Tomcat负责创建和管理Session,并提供了多种持久化方案来存储Session。

思考: 上面提到 HTTP 的特点是无状态的,多个请求之间是没有关系的,这是不是矛盾了?

Http的无状态我理解是指不同请求间协议内容无相关性,即本次请求与上次请求没有内容的依赖关系,本次响应也只针对本次请求的数据,至于服务器应用程序为用户保存的状态是属于应用层,与协议是无关的。
keep-alive表示tcp的连接可以复用,指的是利用已有的传输通道进行http协议内容的传输,省去创建/关闭连接的开销达到提升性能的效果。应用程序其实一般不关心这次Http请求的TCP传输细节,只关心Http协议的内容,因此只要复用tcp连接时做好必要的数据重置,是不算有状态的。