文章目录
写在前面:
博主在字节一面的时候,面试官就问我:浏览器输入URL之后,会发生什么?
虽然博主心里知道面试官想考察的内容是对网络包传输的流程,但是当时还是答得不是很好,故决定总结一系列文章来好好讲讲网络相关知识。
此为系列第二讲,讲的内容是关于HTTP协议的。
博主当时的回答
博主当时的回答是这样的:
当用户输入一个URL之后,浏览器会根据HTTP/HTTPS协议将该请求逐个经过TCP/IP协议栈进行封装。在应用层除了根据HTTP/HTTPS协议添加报头之外,还会根据DNS协议去查询URL所对应的服务器,获取该服务器的IP地址。然后将该IP添加到网络包的目的IP中。之后和服务器建立TCP三次握手,之后服务器响应浏览器的请求,讲请求包发给浏览器。客户端收到请求包之后会根据请求包内的内容将资源渲染给用户。之后,如果是短链接,会进行TCP四次挥手;如果是长链接,则双方会建立相关信息维护这条链接。
今天的文章就是去讲HTTP协议在这个过程中扮演了什么样的角色。
但是,讲HTTP扮演的角色之前,捋一捋HTTP也是很重要的!
HTTP概况
HTTP(HyperText Transfer Protocol)协议的中文名是超文本传输协议,其是一个属于应用层的面向对象的协议,也是web的核心!在【RFC 1945 】和【RFC 2616】中进行了定义。HTTP协议主要由两部分组成:一个客户机程序和一个服务器,他们运行在不同的端系统,通过交换HTTP报文进行会话。HTTP定义了这些报文的格式以及客户机和服务器是如何进行报文交换的。
因为Web浏览器实现了HTTP的客户端,所以在Web环境中,浏览器和客户机两个概念是等同的。Web服务用语存储Web对象,每个对象由URL寻址。Web服务器实现了HTTP的服务器端。
HTTP协议就是定义了客户端和服务器端的通信方式。其交互过程大致如下:当用户请求一个Web页面时,浏览器向服务器发出对该页面中所包含对象的HTTP请求报文,服务器接收请求报文并用包含这些对象的HTTP响应报文进行响应。
HTTP协议为什么选择TCP协议
HTTP协议使用TCP协议作为支撑它的运输层协议。HTTP客户机发起一个与服务器的TCP连接,一旦连接建立,浏览器就可以服务器进程通过套接字接口进行HTTP报文交换。也正是因为使用的是TCP协议,所以浏览器发出的每个HTTP请求报文最终都能完整地到达客户机,即HTTP协议不用担心数据丢失,也不用担心TCP是如何从网络的数据丢失和乱序故障中恢复的,那是TCP协议栈底层的工作。
另外值得提的是,服务器向浏览器发送被请求的文件时,并不存储任何关于该客户机的状态信息。假如某个浏览器几秒内重复请求同一对象,服务器并不会因为刚刚发送过了就不再做出反应,而是重新发送该对象。因为HTTP服务器并不保存关于浏览器的任何信息,这也是我们为什么说HTTP是个无状态协议的原因。
相关web术语(选看)
Web页面(Web page)是由对象组成的。对象简单来说就是文件,如HTML文件,JPEG图形文件,这些文件可以通过一个URL地址寻址。
URL:
URL则是一种特殊的URI,标识着互联网上的资源。一般格式为:
http://host[":" port][abs_path]
比如说,在浏览器输入www.guet.edu.cn
,其就会被转换成http://192.168.0.116:8000/index.jsp
多数的Web页面含有一个基本的HTML文件以及几个引用对象。假如:如果1个Web页面包含HTML文本和5个JPEG图形文件,那么这个Web页面有6个对象。在基本HTML文件中通过对象的URL地址对对象进行引用。
持久连接和非持久连接
当客户机 / 服务器的交互运行于TCP协议之上时,应用程序的开发者如果对每个请求 / 响应对都是经过一个单独的TCP连接发送,那么就是非持久连接。如果对于所有的请求以及响应的都是经过相同的TCP连接发送,那么就是持久连接。本质上来说就是客户机和服务器是否会维护这个连接信息。
HTTP既可以使用非持久连接,也可以使用持久连接,默认方式是持久连接。
HTTP非持久连接
在非持久连接的情况下,从服务器向客户机传送一个Web页面会进行哪些步骤呢?
(假如说一个页面有一个基本的HTML文件和5个JPEG图形,且其位于同一服务器上,URL为:
http://www.shenmingik.com/html/file/test.index
)
- HTTP浏览器会在端口号80发起一个到服务器
www.shenmingik.com
的TCP连接。 - HTTP浏览器经它的套接字向服务器发送一个HTTP报文,其中包含了请求资源路径:
/html/file/test.index
- HTTP服务器进程经其套接字接受该请求报文,从磁盘中请求出响应资源并在一个HTTP响应报文中封装对象,经套接字发送出去
- HTTP服务器断开该TCP连接,进行四次挥手
- 浏览器接受响应报文,TCP连接关闭。
- 浏览器渲染HTTP资源
- 对每个对象重复前面6步
上面的步骤举例说明了非持久连接的使用,每个TCP连接在服务器返回对象之后就关闭。在本例中,会简历1+5=6次TCP连接。
注:
在上面的步骤中,我们没有明确指定浏览器获取这5个JPEG对象时使用串行TCP连接还是并行TCP连接。事实上,可以设置浏览器以控制并行度。默认方式下,大部分浏览器打开5~10个并行的TCP连接,而每个连接处理一个响应-请求事务。如果将最大并行连接数设置为1,这样10个连接就会以串行方式建立。
持久连接
非持久连接有一些缺点。
- 首先,必须为每个请求的对象建立和维护一个全新的连接。对于每个这样的连接,在客户机和服务器都要分配TCP缓冲区和变量,这给服务器带来了严重的负担。
- 其次,一个对象的传输时延为2个RTT(下面会介绍RTT)
在持久连接的情况下,服务器在发送响应后保持该TCP连接打开。在相同的客户机和服务器之间的后续请求和响应报文可以通过相同的连接进行传送。特别是像刚刚那么一个HTML+五个JPEG就完全可以用单个持久TCP连接继续传送。
更有甚者,位于同一服务器上的多个Web从该服务器发送给同一客户机时,可以在单个持久TCP上进行。对于这些对象的请求,可以一个接一个地打出,而不必等待未决的请求的回答。
一般来说,如果一个连接经过一定时间间隔仍未被使用,HTTP服务器就会关闭此连接。
RTT往返时间
我们来估算一下一个从浏览器出发的请求报文到服务器返回并且用户接收到整个请求为止所花费的事件。为此,我们给出往返时间的定义:一个分组从客户端到服务器再返回客户端所花费的时间。
RTT中包括分组传播时延,分组在中间路由器和交换机上的排队时延以及分组处理时延。
从用户点击一个超链接来看往返时间RTT
当用户点击一个超链接,浏览器会向服务器发起一个TCP连接请求,这涉及到一个TCP三次握手的过程:客户机向服务器发送一个SYN同步报文,服务器收到SYN报文之后会将客户机这个连接请求放入一个半连接表中,然后向客户机发送一个SYN+ACK同步确认报文。客户机收到服务器发送的SYN报文之后,向服务器发送一个ACK确认报文,服务器收到之后将此连接信息放入全连接表中。
一个RTT等于三次握手中前两个部分所耗费的时间。不过HTTP这里会在最后一个客户机发送的ACK确认报文结合一个HTTP请求报文。一旦该请求到达服务器,服务器向该TCP连接发送HTML文件。该请求响应又耗费了一个RTT。
HTTP报文格式
HTTP规约【RFC 2616】包含了对HTTP报文格式的定义。HTTP报文有两种:请求报文和响应报文,下面讨论这两种报文。
请求报文
下面是一个典型的HTTP请求报文:
GET /html/file/test.html HTTP/1.1
Host: www.shenmingik.com
Connection: close
User-agent: Mozilla/4.0
Accept-language: en
很明显,这个报文是用普通ASCII文本书写的。虽然说该报文只有五行,但是实际的请求报文可以有更多行或仅有一行。HTTP请求报文的第一行叫做请求行,其后继的行叫做首部行。请求行有三个字段:方法字段、URL字段和HTTP协议版本字段。方法字段可以取值GET、POST
、HEAD
、PUT
和DELETE
。绝大部分的HTTP请求报文使用GET方法。当浏览器请求一个对象时,使用GET方法,在URL字段填写该对象的URL地址,本例中就是根据HTTP/1.1
来请求资源/html/file/test.html
.
方法名 | 释义 |
---|---|
GET | 查看数据 |
PUT | 更新数据 |
DELETE | 删除数据 |
POST | 创建数据 |
注:
HEAD方法类似于GET方法。当服务器收到使用HEAD方法的请求时,会用一个HTTP报文进行响应,但是并不返回请求对象。开发者一般使用其进行故障跟踪
然后我们来看一下本例中的首部行。
Host: www.shenmingik.com
:定义了目标所在的主机。Connection: close
:浏览器告诉服务器使用非持久连接。User-agent: Mozilla/4.0
:首部行用来定义用户代理,即向服务器发送请求的浏览器类型。这里的Mozilla/4.0指的是Netscape浏览器Accept-language: en
:这里表示使用该对象的英格力士版本
下图是HTTP报文通用格式的图,在首部行之后有一个实体注意。使用GET
方法的时候该实体主体为空,而使用POST
方法的时候才会使用。
HTTP响应报文
我们再来看个典型的HTTP响应报文。该响应报文是对上面的例子中请求报文的响应。
HTTP/1.1 200 OK
Connection: close
Date: Thu, 10 Jun 2021 19:38:15 GMT
Server: Apache/1.3.0(Unix)
Last-Modified: Thu, 19 Jun 2021 19:31:16 GMT
Content-Length: 6821
Content-Type: text/html
这个响应报文主要分为三个部分:一个初始状态行、六个首部行、然后是实体主体。实体主体部分是报文的主体,即它包含了所请求的对象本身。状态行有三个字段:协议版本、状态码和相应状态信息。在此报文中,状态行指示服务器使用的协议是HTTP/1.1,并且一切正常。
然后我们再来看看首部行:
Connection: close
:表示客户机在发送报文后关闭了该TCP连接Date: Thu, 10 Jun 2021 19:38:15 GMT
:表示服务器产生并发送该响应报文的日期和时间Server: Apache/1.3.0(Unix)
:表示产生报文的服务器Last-Modified: Thu, 19 Jun 2021 19:31:16 GMT
:对象创建或最后修改的日期和时间Content-Length: 6821
:被发送对象的字节数Content-Type: text/html
:指示了实体主体中的对象时HTML文本
通过这个例子,我们再来看看响应报文的通用格式:
常见状态码
状态码 | 英文字段 | 释义 |
---|---|---|
200 | OK | 请求成功,信息包含在返回的响应报文中 |
301 | Move Permanently | 请求的对象已经被永久转移了 |
400 | Bad Request | 通用差错,表示请求服务器理解不了 |
404 | Not Found | 被请求的文档不在服务器上 |
505 | HTTP Version Not Supported | 服务器不支持此HTTP版本号 |
用户偏好推荐:cookie
前面提到了HTTP服务器是无状态的。虽然这方便了开发者去实现高并发,但是一个Web站点通常希望能够识别用户(既可以限制访问,又能关联内容和用户)。为此,HTTP使用了cookie。其在【RFC 2109】中进行定义,它允许站点跟踪用户。
cookie技术主要有四个组成部分:
- 在HTTP响应报文中有一个cookie首部行
- 在HTTP请求报文中有一个cookie首部行
- 在用户端系统中保留有一个cookie文件,由浏览器管理
- 在Web站点有个后端数据库
下面我们就结合一个例子和图来理解cookie:
假如说我们第一次访问Amazon.com,那么当请求报文到达Amazon Web服务器时,该Web站点将产生一个唯一识别码,并以此作为索引在它后端数据库中产生一个表项。接下来Amazon服务器用一个包含Set-cookie
首部行的HTTP响应报文对我们的浏览器进行响应,其中Set-cookie
行中含有识别码:
Set-cookie:1678
当我们的浏览器收到该HTTP响应报文时,它会看到该Set-cookie
首部。浏览器就会在它管理的特定的cookie文件中添加一行,其中包含该服务器的主机名和Set-cookie
首部中的识别码。
当我们继续用浏览器浏览Amazon时,每请求一个Web页面,其浏览器就会从它的cookie文件中获取这个网站的识别码,并放到请求报文中含有识别码的cookie首部行中。每个请求报文都包含以下首部行:
Cookie:1678
在这种方式下,Amazon可以跟踪用户在该站点的活动。Amazon并不需要知道用户的名字,但是它知道cookie 1678访问了哪些页面,按照什么顺序,什么时间。
Web缓存
Web缓存器也叫代理服务器,它是能够代表初始Web服务器来满足HTTP请求的网络实体。Web缓存器有自己的磁盘存储空间,并在该存储空间中保存最近请求过的对象的拷贝。
我们可以配置用户的浏览器,使得用户的所有HTTP请求首先指向Web缓存器。一旦配置了浏览器,每个浏览器对一个对象的请求首先会被定向到Web缓存器。
一般而言,Web缓存器由ISP(运营商)购买并安装。在因特网上部署Web缓存器有两个原因。首先,Web缓存器可以大大减少对客户机请求的响应时间。其次,Web缓存器可以大大减少一个机构内部网与因特网接入链路上的通信量。
参考文献
[1]计算机网络自顶向下方法.第二章