HTTP

最后更新:2018-12-20

本文以HTTP请求和响应的过程来讲解涉及到的相关知识点。

1.HTTP请求和响应步骤

以上完整表示了HTTP请求和响应的7个步骤

建立TCP连接->发送请求行->发送请求头->(到达服务器)发送状态行->发送响应头->发送响应数据->断TCP连接

建立TCP连接

在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建 Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则, 只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。

Web浏览器向Web服务器发送请求行

一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET /sample/hello.jsp HTTP/1.1。

Web浏览器发送请求头

浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。

Web服务器应答

客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。

Web服务器发送应答头

正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。

Web服务器向浏览器发送数据

Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。

Web服务器关闭TCP连接

一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码: Connection:keep-alive

TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

下面从TCP/IP协议模型的角度来理解HTTP请求和响应如何传递的。

2. TCP/IP协议

TCP/IP协议模型(Transmission Control Protocol/Internet Protocol),包含了一系列构成互联网基础的网络协议,是Internet的核心协议,通过20多年的发展已日渐成熟,并被广泛应用于局域网和广域网中,目前已成为事实上的国际标准。TCP/IP协议簇是一组不同层次上的多个协议的组合,通常被认为是一个四层协议系统,与OSI的七层模型相对应。

HTTP协议就是基于TCP/IP协议模型来传输信息的。

更多内容参考 https://edgar615.github.io/tcp.html

下面这张图从TCP/IP模型的角度更清楚明白地说明了一次HTTP请求与响应的过程。

3. HTTP协议

HTTP 是一种 超文本传输协议(Hypertext Transfer Protocol),它可以拆成三个部分:

  • 超文本
  • 传输
  • 协议

3.1. 协议

在生活中,我们也能随处可见「协议」,例如:

  • 刚毕业时会签一个「三方协议」;
  • 找房子时会签一个「租房协议」;

生活中的协议,本质上与计算机中的协议是相同的,协议的特点:

  • 」字,代表的意思是必须有两个以上的参与者。例如三方协议里的参与者有三个:你、公司、学校三个;租房协议里的参与者有两个:你和房东。
  • 」字,代表的意思是对参与者的一种行为约定和规范。例如三方协议里规定试用期期限、毁约金等;租房协议里规定租期期限、每月租金金额、违约如何处理等。

针对 HTTP 协议,我们可以这么理解。

HTTP 是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范(两个以上的参与者),以及相关的各种控制和错误处理方式(行为约定和规范)。

3.2. 传输

所谓的「传输」,很好理解,就是把一堆东西从 A 点搬到 B 点,或者从 B 点 搬到 A 点。

别轻视了这个简单的动作,它至少包含两项重要的信息。

HTTP 协议是一个双向协议

我们在上网冲浪时,浏览器是请求方 A ,百度网站就是应答方 B。双方约定用 HTTP 协议来通信,于是浏览器把请求数据发送给网站,网站再把一些数据返回给浏览器,最后由浏览器渲染在屏幕,就可以看到图片、视频了。

数据虽然是在 A 和 B 之间传输,但允许中间有中转或接力

就好像第一排的同学想穿递纸条给最后一排的同学,那么传递的过程中就需要经过好多个同学(中间人),这样的传输方式就从「A < — > B」,变成了「A <-> N <-> M <-> B」。

而在 HTTP 里,需要中间人遵从 HTTP 协议,只要不打扰基本的数据传输,就可以添加任意额外的东西。

针对传输,我们可以进一步理解了 HTTP。

HTTP 是一个在计算机世界里专门用来在两点之间传输数据的约定和规范。

3.3. 超文本

HTTP 传输的内容是「超文本」。

我们先来理解「文本」,在互联网早期的时候只是简单的字符文字,但现在「文本」。的涵义已经可以扩展为图片、视频、压缩包等,在 HTTP 眼里这些都算做「文本」。

再来理解「超文本」,它就是超越了普通文本的文本,它是文字、图片、视频等的混合体最关键有超链接,能从一个超文本跳转到另外一个超文本。

HTML 就是最常见的超文本了,它本身只是纯文字文件,但内部用很多标签定义了图片、视频等的链接,在经过浏览器的解释,呈现给我们的就是一个文字、有画面的网页了。

OK,经过了对 HTTP 里这三个名词的详细解释,就可以给出比「超文本传输协议」这七个字更准确更有技术含量的答案:

HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。

3.4. 与 HTTP 有关的协议

在互联网中,任何协议都不会单独的完成信息交换,HTTP 也一样。虽然 HTTP 属于应用层的协议,但是它仍然需要其他层次协议的配合完成信息的交换,那么在完成一次 HTTP 请求和响应的过程中,需要哪些协议的配合呢?一起来看一下

TCP/IP

TCP/IP 协议你一定听过,TCP/IP 我们一般称之为协议簇,什么意思呢?就是 TCP/IP 协议簇中不仅仅只有 TCP 协议和 IP 协议,它是一系列网络通信协议的统称。而其中最核心的两个协议就是 TCP / IP 协议,其他的还有 UDP、ICMP、ARP 等等,共同构成了一个复杂但有层次的协议栈。

TCP 协议的全称是 Transmission Control Protocol 的缩写,意思是传输控制协议,HTTP 使用 TCP 作为通信协议,这是因为 TCP 是一种可靠的协议,而可靠能保证数据不丢失。

IP 协议的全称是 Internet Protocol 的缩写,它主要解决的是通信双方寻址的问题。IP 协议使用 IP 地址 来标识互联网上的每一台计算机,可以把 IP 地址想象成为你手机的电话号码,你要与他人通话必须先要知道他人的手机号码,计算机网络中信息交换必须先要知道对方的 IP 地址。(关于 TCP 和 IP 更多的讨论我们会在后面详解)

DNS

你有没有想过为什么你可以通过键入 www.google.com 就能够获取你想要的网站?我们上面说到,计算机网络中的每个端系统都有一个 IP 地址存在,而把 IP 地址转换为便于人类记忆的协议就是 DNS 协议

DNS 的全称是域名系统(Domain Name System,缩写:DNS),它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。

URI / URL

我们上面提到,你可以通过输入 www.google.com 地址来访问谷歌的官网,那么这个地址有什么规定吗?我怎么输都可以?AAA.BBB.CCC 是不是也行?当然不是的,你输入的地址格式必须要满足 URI 的规范。

URI的全称是(Uniform Resource Identifier),中文名称是统一资源标识符,使用它就能够唯一地标记互联网上资源。

URL的全称是(Uniform Resource Locator),中文名称是统一资源定位符,也就是我们俗称的网址,它实际上是 URI 的一个子集。

URI 不仅包括 URL,还包括 URN(统一资源名称),它们之间的关系如下

HTTPS

HTTP 一般是明文传输,很容易被攻击者窃取重要信息,鉴于此,HTTPS 应运而生。HTTPS 的全称为 (Hyper Text Transfer Protocol over SecureSocket Layer),全称有点长,HTTPS 和 HTTP 有很大的不同在于 HTTPS 是以安全为目标的 HTTP 通道,在 HTTP 的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在 HTTP 的基础上增加了 SSL 层,也就是说 HTTPS = HTTP + SSL。(这块我们后面也会详谈 HTTPS)

4. HTTP 请求响应过程

我们假设访问的 URL 地址为 http://www.someSchool.edu/someDepartment/home.index,当我们输入网址并点击回车时,浏览器内部会进行如下操作

  • DNS服务器会首先进行域名的映射,找到访问www.someSchool.edu所在的地址,然后HTTP 客户端进程在 80 端口发起一个到服务器 www.someSchool.edu 的 TCP 连接(80 端口是 HTTP 的默认端口)。在客户和服务器进程中都会有一个套接字与其相连。
  • HTTP 客户端通过它的套接字向服务器发送一个 HTTP 请求报文。该报文中包含了路径 someDepartment/home.index 的资源,我们后面会详细讨论 HTTP 请求报文。
  • HTTP 服务器通过它的套接字接受该报文,进行请求的解析工作,并从其存储器(RAM 或磁盘)中检索出对象 www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到 HTTP 响应报文中,并通过套接字向客户进行发送。
  • HTTP 服务器随即通知 TCP 断开 TCP 连接,实际上是需要等到客户接受完响应报文后才会断开 TCP 连接。
  • HTTP 客户端接受完响应报文后,TCP 连接会关闭。HTTP 客户端从响应中提取出报文中是一个 HTML 响应文件,并检查该 HTML 文件,然后循环检查报文中其他内部对象。
  • 检查完成后,HTTP 客户端会把对应的资源通过显示器呈现给用户。

至此,键入网址再按下回车的全过程就结束了。上述过程描述的是一种简单的请求-响应全过程,真实的请求-响应情况可能要比上面描述的过程复杂很多。

5. HTTP请求报文

一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。

5.1. 请求行

请求行分为三个部分:请求方法、请求地址和协议版本

请求方法

HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。

最常的两种GET和POST,如果是RESTful接口的话一般会用到GET、POST、DELETE、PUT。

请求地址

URL:统一资源定位符,是一种自愿位置的抽象唯一识别方法。

组成:<协议>://<主机>:<端口>/<路径>

端口和路径有时可以省略(HTTP默认端口号是80)

协议版本

协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1

5.2. 请求头部

请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔。

常见请求头如下

请求头部的最后会有一个空行,表示请求头部结束,接下来为请求数据,这一行非常重要,必不可少。

5.3. 请求数据

可选部分,比如GET请求就没有请求数据。

下面是一个POST方法的请求报文:

POST  /index.php HTTP/1.1    #请求行
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2  #请求头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://localhost/
Content-Length:25
Content-Type:application/x-www-form-urlencoded
  空行
username=aa&password=1234  #请求数据

6. HTTP响应报文

HTTP响应报文主要由状态行、响应头部、空行以及响应数据组成。

6.1. 状态行

由3部分组成,分别为:协议版本,状态码,状态码描述。

其中协议版本与请求报文一致,状态码描述是对状态码的简单描述,所以这里就只介绍状态码。

状态码

1xx

1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。

2xx

2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。

200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据。

204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。

206 Partial Content」是应用于 HTTP 分块下载或断电续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。

3xx

3xx 类状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向

301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。

302 Moved Permanently」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。

301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。

304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。

4xx

4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。

400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误。

403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。

404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。

5xx

5xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。

500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。

501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。

502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。

503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思。

6.2. 响应头部

与请求头部类似,为响应报文添加了一些附加信息

常见响应头部如下:

6.3. 响应数据

用于存放需要返回给客户端的数据信息。

下面是一个响应报文的实例:

HTTP/1.1 200 OK  #状态行

Date: Sun, 17 Mar 2013 08:12:54 GMT  #响应头部
Server: Apache/2.2.8 (Win32) PHP/5.2.5
X-Powered-By: PHP/5.2.5
Set-Cookie: PHPSESSID=c0huq7pdkmm5gg6osoe3mgjmm3; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 4393
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8

空行
<html>  #响应数据
<head>
<title>HTTP响应示例<title>
</head>
<body>
Hello HTTP!
</body>
</html>

7. HTTP 特性

HTTP 最凸出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。

简单

HTTP 基本的报文格式就是 header + body,头部信息也是 key-value 简单文本的形式,易于理解,降低了学习和使用的门槛。

灵活和易于扩展

HTTP协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充。

同时 HTTP 由于是工作在应用层( OSI 第七层),则它下层可以随意变化。

HTTPS 也就是在 HTTP 与 TCP 层之间增加了 SSL/TLS 安全传输层,HTTP/3 甚至把 TCPP 层换成了基于 UDP 的 QUIC。

应用广泛和跨平台

互联网发展至今,HTTP 的应用范围非常的广泛,从台式机的浏览器到手机上的各种 APP,从看新闻、刷贴吧到购物、理财、吃鸡,HTTP 的应用片地开花,同时天然具有跨平台的优越性。

那它的缺点呢

HTTP 协议里有优缺点一体的双刃剑,分别是「无状态、明文传输」,同时还有一大缺点「不安全」。

无状态双刃剑

无状态的好处,因为服务器不会去记忆 HTTP 的状态,所以不需要额外的资源来记录状态信息,这能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。

无状态的坏处,既然服务器没有记忆能力,它在完成有关联性的操作时会非常麻烦。

例如登录->添加购物车->下单->结算->支付,这系列操作都要知道用户的身份才行。但服务器不知道这些请求是有关联的,每次都要问一遍身份信息。

对于无状态的问题,解法方案有很多种,其中比较简单的方式用 Cookie 技术。

Cookie 通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。

相当于,在客户端第一次请求后,服务器会下发一个装有客户信息的「小贴纸」,后续客户端请求服务器的时候,带上「小贴纸」,服务器就能认得了了

明文传输双刃剑

明文意味着在传输过程中的信息,是可方便阅读的,通过浏览器的 F12 控制台或 Wireshark 抓包都可以直接肉眼查看,为我们调试工作带了极大的便利性。

但是这正是这样,HTTP 的所有信息都暴露在了光天化日下,相当于信息裸奔。在传输的漫长的过程中,信息的内容都毫无隐私可言,很容易就能被窃取,如果里面有你的账号密码信息,那你号没了。

不安全

HTTP 比较严重的缺点就是不安全:

  • 通信使用明文(不加密),内容可能会被窃听。比如,账号信息容易泄漏,那你号没了。
  • 不验证通信方的身份,因此有可能遭遇伪装。比如,访问假的淘宝、拼多多,那你钱没了。
  • 无法证明报文的完整性,所以有可能已遭篡改。比如,网页上植入垃圾广告,视觉污染,眼没了。

HTTP 的安全问题,可以用 HTTPS 的方式解决,也就是通过引入 SSL/TLS 层,使得在安全上达到了极致。

8. HTTP/1.1 的性能

HTTP 协议是基于 TCP/IP,并且使用了「请求 - 应答」的通信模式,所以性能的关键就在这两点里。

长连接

早期 HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无畏的 TCP 连接建立和断开,增加了通信开销。

为了解决上述 TCP 连接问题,HTTP/1.1 提出了长连接的通信方式,也叫持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。

持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

管道网络传输

HTTP/1.1 采用了长连接的方式,这使得管道(pipeline)网络传输成为了可能。

即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求。

但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求。要是 前面的回应特别慢,后面就会有许多请求排队等着。这称为「队头堵塞」。

队头阻塞

「请求 - 应答」的模式加剧了 HTTP 的性能问题。

因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是「队头阻塞」。好比上班的路上塞车

总之 HTTP/1.1 的性能一般般,后续的 HTTP/2 和 HTTP/3 就是在优化 HTTP 的性能。

9. 参考资料

https://www.jianshu.com/p/c1d6a294d3c0

https://mp.weixin.qq.com/s/bUy220-ect00N4gnO0697A

https://mp.weixin.qq.com/s/vCaYFSUxYRVfKHx6btDjqQ

Edgar

Edgar
一个略懂Java的小菜比