你好,我是 HTTP —— HTTP 基础介绍

528 阅读10分钟

在浏览器打开一个网页,我们往往会在地址栏的开头看到 "http" 或者是 "https", 那这到底是什么呢?

还有一些情况下,我们打开某个网页,显示的是 “404 Not Found” 或者 "500 Server Error" 之类的,并没有期望的内容,这些又代表什么呢?

上面所提到的,都和一个叫 HTTP 的同学有关。

本期节目,让我们走近 HTTP.

HTTP 的学名是 Hyper Text Transfer Protocol, 翻译成中文就是“超文本传输协议”,看到这里,可能有点轮廓了,它是和传输相关的。

这个超文本传输协议定义了 Web 客户端向服务器请求页面的方式,也定义了 Web 服务器向客户传送页面的方式。也就是说,在浏览器中打开的网页,都是基于 HTTP 这个协议来传输的。

HTTP 是通过客户端的请求和服务端的响应,来达成通信的。

下面我们把镜头对准客户端,看看它是如何请求的。

请求报文

客户端的请求信息要发给服务端,告诉服务端我需要什么样的数据。这里的请求信息,称之为请求报文。

请求报文由请求行,首部行和请求实体组成,请求行和首部行的每一行由回车换行符结束,首部行的下一行还有一组回车换行,紧跟着是请求实体。

GET

举个栗子,比如要取得网址 www.somesite.com/list/people 的资源,基本的请求报文如下:

GET /list/people HTTP/1.1
Host: www.somesite.com
Connection: close
User-Agent: Mozilla/5.0
Accept-Language: en

上面的第一行即为请求行,其中 GET 代表的是请求方法;/list/people 是请求资源的 URI; 而 HTTP/1.1 则是该请求的 HTTP 版本号,代表该请求是基于 HTTP 1.1 版本的。

接下来从 Host 逐行往下到 Accept-Language,都属于 HTTP 请求报文的首部行。

Host 表明了资源所在主机;Connection: close 告诉服务器不必采用持续连接(下面会提到),服务器在发送完响应信息后会关闭这次连接,此处若是 Connection: keep-alive 则表明要采用持续连接;User-Agent 指明了发送请求浏览器的类型;Accept-Language: en 代表浏览器期望该资源的英语版本,若服务器没有英语版本,则返回默认的版本。首部行字段有个细节,就是每个字段的冒号之后,都有一个空格。

这个示例里面的请求首部行只是几个常见的字段,在真实的请求当中,肯定会有更多的字段。

在请求行和首部行的末尾都有回车换行符,即 \r\n, 所以我们能看到上面的请求都是一行行分开的。在首部行的末尾的下一行,还有一组回车换行符,若请求存在请求实体将与首部行有一行的间隔。

从请求行的方法字段我们可知,这是一个 GET 请求,而 GET 请求是没有请求实体的。所以上面的报文只有请求行和首部行。

POST

假如是一个 POST 请求,向服务器上传一些信息,那么请求报文可能是这样的:

POST /list/people HTTP/1.1
Host: www.somesite.com
Connection: close
User-Agent: Mozilla/5.0
Accept-Language: en
Content-Type: application/x-www-form-urlencoded
Content-Length: 16

name=jack&age=18

上面的 name=jack&age=18是该次 POST 请求传送给服务器的数据,也就是请求报文的请求实体。肉眼可见,请求实体与首部行相隔一行。

收到客户端浏览器的请求之后,服务器当然要给人家一个答复。这个答复就是服务器的响应报文。

响应报文

和请求报文类似,响应报文由状态行,首部行和实体组成。

话不多说,举个栗子,

HTTP/1.1 200 OK
Connection: close
Date: Thu, 26 Mar 2020 08:39:52 GMT
Server: nginx/1.15.10
Last-Modified: Sat, 21 Mar 2020 13:23:02 GMT
Content-Length: 215
Content-Type: text/html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTTP Respose</title>
</head>
<body>
  <h1>Heelo</h1>
</body>
</html>

上面报文的第一行即为响应报文的状态行,状态行包括三个字段:协议版本字段,状态码以及状态信息。其中 HTTP/1.1 表明了协议及其版本;200 即为状态码,常见的状态码还有 404301 等;OK 是状态信息,表示请求和响应都没问题。像状态码 404 对应的状态信息是 Not Found, 表示服务器找不到该资源;301 则对应 Moved Permanently, 表明该资源已经被永久移动到新的 URI, 返回信息中也会包含新的 URI.

状态行之后,就是响应报文的首部行。其中 Date 表示服务器产生并发送该响应报文的时间;Server 和请求报文中的 User-Agent 类似,在这里表明响应来自 Nginx 服务器;Last-Modified 表示资源最后一次修改的时间;Cotent-Length 表示资源的字节数,Content-Type 表示资源的类型。

首部行之后,便是响应实体。和请求报文一样,首部行与实体相隔一行。这里可以看到,返回给客户端的资源是 HTML 文档。

无状态和 Cookie

HTTP 是无状态的,也就是说 HTTP 不对客户端和服务器的通信状态进行保存,鱼还有七秒钟记忆,这货更狠,直接没有记忆力。就算某个客户端在几秒钟内就进行了第二次请求,服务器也不会因为刚刚已经发送过同样的内容而停止响应,而是照发一次,因为它并不记得第一次请求。

HTTP 这种无状态的特性,简化了 HTTP 服务器的设计,并且允许工程师去开发可以同时处理数以千计的 TCP 连接的高性能 Web 服务器。

​ —— 《计算机网络——自顶向下方法》

但是假如用户登录了一个站点,需要进行一些登录之后才能做的操作,而服务器保持无状态,完全记不得用户曾经登录过,那用户只能不停地登录直到砸键盘。

为了给 HTTP 添加状态,大多数站点都使用了 Cookie.

例如,用户发起登录请求,服务器发送给客户端的响应报文会包含一个 Set-Cookie 的首部行,字段值可以为服务器给改用户分配的 ID,比如说 uuid=9527。浏览器收到这样的响应,会在浏览器的 cookie 里添加这个信息。并且,在后续的请求中,在请求行会添加一个 Cookie 字段,来让服务器知道,这些请求都发自已登录的用户 9527。这样一来,就在 HTTP 中添加了状态,让服务器可以识别用户。

Cookie 技术一共有 4 个组件:

  1. 在响应报文中的一个首部行

  2. 在客户端保存的 Cookie

  3. 在请求报文中的一个首部行

  4. 在 Web 站点后端的一个数据库

非持久连接和持久连接

非持久连接

初始版本中,每请求一次就要断开一次连接,这就是非持久连接。因为早期通信,都是体积很小的文本传输。非持久连接尚可胜任。

但随着技术的发展,文档中可能包含大量图片或其他资源。若还是采用非持久连接,每请求一张图片,都要建立一次 TCP 连接。

假如有一个网页有十张图片,第一次请求得到网页的 HTML 文档,文档里面包含了十张图片的 URL. 接下来就是请求十张图片,每张图片就要一次请求,整个文档加载下来,就是十一个请求。假如成百上千人同时请求这个网页,服务器哪顶得住。

持久连接

HTTP 1.1 和部分 HTTP 1.0 实现了持久连接,即未声明连接断开,则保持连接。这样一来,就大大减少了不必要的连接建立和断开所造成的花销。请求包含十张图片的网页,从发起请求开始,保持连接打开,HTML 文档及其所包含的十张图片都可以在一个连接内传送完成。

持久连接使得管线化请求成为可能,即在一个连接中,不必等待上一个请求收到响应,即可发送下一个请求,相当于有多个并行的请求,这样一来,使页面的内容加载得更快。

HTTP 1.1 默认就是持久连接,客户端会在持久连接上持续发送请求,若服务器想要断开连接,则设定响应报文首部行的 Connection 字段值为 Close.

HTTP 1.1 之前默认都是非持久连接,若要开启持久连接,需要设置请求和响应报文首部行的 Connection 字段的值为 Keep-Alive.

HTTP 和 HTTPS

在浏览器的地址栏,除了 " http " 开头,现在更为常见的是 "https" 开头的网址。那这个 HTTPS 是什么呢?它和 HTTP 有什么关系?

简单来说,HTTPS 就是安全的 HTTP. 它的全称是 HTTP Secure, 即超文本安全传输协议。

HTTP 的缺陷

HTTP 的安全性并不好,主要有以下几点:

  • 通信使用明文,可能会被窃听
  • 不验证通信方的身份,可能遭遇伪装
  • 无法验证报文的完整性,报文可能遭到篡改

要解决这些问题,就需要安全的 HTTP,即 HTTPS.

HTTPS

HTTP 中没有加密机制,但可以通过和 SSL (Secure Socket Layer, 安全套接层) 或 TLS (Transport Layer Security, 安全传输层协议) 的组合使用,来加密通信内容,这就是 HTTPS,因此 HTTPS 又称为 HTTP over SSL 或 HTTP over TLS.

这里拿 SSL 来举例。

用 SSL 建立安全的通信线路之后,就可以在这条线路上进行通信,这是对通信的线路进行加密。

使用 SSL 还可以确认通信方的身份,SSL 对通信方的确认是通过一种叫做证书的手段。证书由权威的第三方颁发,用以证明通信双方是是实际存在的,是可信赖的。而在技术上来说,伪造证书是及其困难的。有时候,我们访问某个网页,浏览器会显示“此网站的安全证书存在问题”,这就是 SSL 对服务器证书的确认。

在基于 SSL 的通信过程中,应用层发送数据时会附带一种叫做 MAC (Message Authentication Code) 的报文摘要,这种报文摘要能够检查报文是否遭到篡改,从而来保证报文的完整性。

要注意,HTTPS 并不是一种新的协议,它只是通信接口部分被 SSL 替代的 HTTP.

此外,HTTP 的 URL 由 http:// 开头,默认端口是 80,而 HTTPS 的 URL 由 https:// 开头,默认端口为 443.

既然说 HTTPS 有着良好的安全性,那么应该所有的现代站点都要应用 HTTPS 才是,但我们上网的时候,发现不少站点还是用的 HTTP,这是为什么呢?

为什么不一直使用 HTTPS?

不是所有站点都使用 HTTPS,主要有以下几个原因:

  • 通信过程慢,因为要对通信进行处理,导致 HTTPS 通信慢
  • 资源开销大,因为还要对同行双方进行加密解密等处理,需要消耗 CPU 和内存等资源
  • 购买证书的开销

由此可见,使用 HTTPS 还是有一些顾虑。只有在涉及敏感信息如用户信息等情景下,才需要使用 HTTPS.

总结

这就是对 HTTP 的简单介绍,包括 HTTP 报文的结构、HTTP 无状态的特性、非持久连接和持久连接,以及 HTTPS,希望可以给读者留下一个 HTTP 的大致脉络。