HTTP 介绍

HTTP/0.9

20 世纪 90 年代初期的互联网世界非常简陋,计算机处理能力低,存储容量小,网速很 慢,还是一片“信息荒漠”。网络上绝大多数的资源都是纯文本,很多通信协议也都使用纯文本,所以 HTTP 的设计也不可避免地受到了时代的限制。

这一时期的 HTTP 被定义为 0.9 版,结构比较简单,为了便于服务器和客户端处理,它也采用了纯文本格式。蒂姆·伯纳斯 - 李最初设想的系统里的文档都是只读的,所以只允许用“GET”动作从服务器上获取 HTML 文档,并且在响应请求之后立即关闭连接,功能非常有限。

HTTP/1.0

  1. 增加了 HEAD、POST 等新方法
  2. 增加了响应状态码
  3. 引入了协议版本号概念
  4. 引入了 HTTP Header 的概念
  5. 传输的数据不再仅限于文本

但 HTTP/1.0 并不是一个“标准”,只是记录已有实践和模式的一份参考文档,不具有实际 的约束力,相当于一个“备忘录”。

HTTP/1.1

HTTP/1.1 是对 HTTP/1.0 的小幅度修正。但一个重要的区别是:它是一个“正式的标准

  1. 增加了 PUT、DELETE 等新的方法
  2. 增加了缓存管理和控制
  3. 明确了连接管理,允许持久连接
  4. 允许响应数据分块,利于传输大文件
  5. 强制要求 Host 头,让互联网主机托管成为可能

HTTP/2

Google 首先开发了自己的浏览器 Chrome,然后推出了新的 SPDY 协议

Google 通过高额用户占有率,借此顺势把 SPDY 推上了标准的宝座,互联网标准 化组织以 SPDY 为基础开始制定新版本的 HTTP 协议,最终在 2015 年发布了 HTTP/2

  1. 二进制协议
  2. 可发起多个请求
  3. 使用专用算法压缩头部
  4. 允许服务器主动推送数据
  5. 增强了安全性,要求加密通信

HTTP/3

在 HTTP/2 还处于草案之时,Google 又发明了一个新的协议,叫做 QUIC

2018 年,互联网标准化组织 IETF 提议将“HTTP over QUIC”更名 为“HTTP/3”并获得批准

HTTP 是什么?HTTP 又不是什么?

HTTP 中文翻译为超文本标记语言,三个关键字,超文本标记预言

HTTP 是什么

超文本

“超越了普通文本的文本”,它是文字、图片、音频和视频等的混合体,最关键的是含有“超链接”,能够从一个“超文本”跳跃到另一个“超文本”,形成复杂的非线性、网状的结构关系。

传输

  1. 双向传输,但两个浏览器不能通信。服务器可以当客户端,但浏览器只是客户端。
  2. 并没有限制角色,A -> B,可以变成 A -> X -> Y -> B

协议

  1. 协:协议必须要有两个或多个参与者

  2. 议:协议是对参与者的一种行为约定和规范

HTTP 不是什么

因为 HTTP 是一个协议,是一种计算机间通信的规范,所以它不存在“单独的实体”

HTTP 不是一个孤立的协议

俗话说“一个好汉三个帮”,HTTP 也是如此。

在互联网世界里,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外,还有一些协议依赖于 HTTP,例如 WebSocketHTTPDNS 等。这些协议相互交织,构成了一个协议网,而 HTTP 则处于中心地位。

与 HTTP 相关的各种协议

TCP/IP

TCP/IP 协议实际上是一系列网络通信协议的统称,其中最核心的两个协议是TCPIP,其他的还有 UDP、ICMP、ARP 等等,共同构成了一个复杂但有层次的协议栈。

IP 协议是“Internet Protocol”的缩写,主要目的是解决寻址和路由问题,以及如何在两点间传送数据包。IP 协议使用“IP 地址”的概念来定位互联网上的每一台计算机。可以对比一下现实中的电话系统,你拿着的手机相当于互联网上的计算机,而要打电话就必须接入电话网,由通信公司给你分配一个号码,这个号码就相当于 IP 地址。

TCP 协议是“Transmission Control Protocol”的缩写,意思是“传输控制协议”,它位于 IP 协议之上,基于 IP 协议提供可靠的、字节流形式的通信,是 HTTP 协议得以实现的基础。

“可靠”是指保证数据不丢失,“字节流”是指保证数据完整,所以在 TCP 协议的两端可以如同操作文件一样访问传输的数据,就像是读写在一个密闭的管道里“流动”的字节。

DNS

在 TCP/IP 协议中使用 IP 地址来标识计算机,数字形式的地址对于计算机来说是方便了,但对于人类来说却既难以记忆又难以输入。

于是“域名系统”(Domain Name System)出现了,用有意义的名字来作为 IP 地址的等价替代

但想要使用 TCP/IP 协议来通信仍然要使用 IP 地址,所以需要把域名做一个转换,“映射”到它的真实 IP,这就是所谓的“域名解析”。

URL/URI

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

URL(Uniform Resource Locator), 统一资源定位符,也就是我们俗称的“网址”

http://nginx.org/en/download.html

  1. 协议名:http
  2. 主机名:nginx.org
  3. 路径:/en/download.html

HTTPS

全称是“HTTP over SSL/TLS”,也就是运行在 SSL/TLS 协议上的 HTTP。

SSL/TLS 是一个负责加密通信的安全协议,建立在 TCP/IP 之上

SSL,由网景公司发明,当发展到 3.0 时被标准化,改名为 TLS,历史的原因还是有很多人称之为 SSL/TLS,或者直接简称为 SSL

代理

代理(Proxy)是 HTTP 协议中请求方和应答方中间的一个环节,作为“中转站”,既可以转发客户端的请求,也可以转发服务器的应答。

代理有很多的种类,常见的有:

  1. 匿名代理:完全“隐匿”了被代理的机器,外界看到的只是代理服务器;
  2. 透明代理:顾名思义,它在传输过程中是“透明开放”的,外界既知道代理,也知道客户端;
  3. 正向代理:靠近客户端,代表客户端向服务器发送请求;
  4. 反向代理:靠近服务器端,代表服务器响应客户端的请求;

由于代理在传输过程中插入了一个“中间层”,所以可以在这个环节做很多有意思的事情,比如:

  1. 负载均衡:把访问请求均匀分散到多台机器,实现访问集群化;
  2. 内容缓存:暂存上下行的数据,减轻后端的压力;
  3. 安全防护:隐匿 IP, 使用 WAF 等工具抵御网络攻击,保护被代理的机器;
  4. 数据处理:提供压缩、加密等额外的功能。

域名的门道

域名是一个有层次的结构,是一串用“.”分隔的多个单词,最右边的被称为“顶级域名”,然后是“二级域名”,层级关系向左依次降低。

www.baidu.com

  1. www 三级域名
  2. baidu 二级域名
  3. com 顶级域名

DNS 服务器

DNS 的核心系统是一个三层的树状、分布式服务

  1. 根域名服务器:管理顶级域名服务器
  2. 顶级域名服务器:管理各自域名下的权威域名服务器
  3. 权威域名服务器:管理自己域名下主机的 IP 地址

野生的域名服务器

虽然核心的 DNS 系统遍布全球,服务能力很强也很稳定,但如果全世界的网民都往这个系统里挤,即使不挤瘫痪了,访问速度也会很慢。

所以在核心 DNS 系统之外,还有两种手段用来减轻域名解析的压力,并且能够更快地获取结果,基本思路就是“缓存”。

首先,许多大公司、网络运行商都会建立自己的 DNS 服务器,作为用户 DNS 查询的代理,代替用户访问核心 DNS 系统。这些“野生”服务器被称为“非权威域名服务器”,可以缓存之前的查询结果,如果已经有了记录,就无需再向根服务器发起查询,直接返回对应的 IP 地址。

主机映射文件

操作系统里还有一个特殊的“主机映射”文件,域名解析时先根据本文件映射

Linux 里是/etc/hosts

Windows 里是C:\WINDOWS\system32\drivers\etc\hosts

域名解析顺序

操作系统还有 DNS 缓存,浏览器也有 DNS 缓存,每个运营商也会提供本地域名服务器

解析顺序:浏览器缓存 -> DNS Cache -> hosts 文件 -> 本地域名服务器 -> 根域名服务器 -> 顶级域名服务器 -> 权威域名服务器

域名的“新玩法”

有了域名,又有了可以稳定工作的解析系统,于是我们就可以实现比 IP 地址更多的“新玩法”了。

第一种,也是最简单的,“重定向”。因为域名代替了 IP 地址,所以可以让对外服务的域名不变,而主机的 IP 地址任意变动。当主机有情况需要下线、迁移时,可以更改 DNS 记录,让域名指向其他的机器。

第二种,因为域名是一个名字空间,所以可以使用 bind9 等开源软件搭建一个在内部使用的 DNS,作为名字服务器

第三种,基于域名实现的负载均衡。服务端返回所有 IP,客户端选择(客户端负载均和);服务端返回最好主机的 IP(服务端负载均衡)

所带来的问题

  • “域名屏蔽”,对域名直接不解析,返回错误,让你无法拿到 IP 地址,也就无法访问网站;
  • “域名劫持”,也叫“域名污染”,你要访问 A 网站,但 DNS 给了你 B 网站。

HTTP 报文

报文结构

HTTP 协议知识整理

  • 开始行:用于区分是请求报文还是响应报文。
  • 首部行:用于说明浏览器或服务器报文主体的信息。
  • 空行:必须要有个空行隔开
  • 实体主体(请求体、响应体)

HTTP 是一个“纯文本”的协议,所以头数据都是 ASCII 码的文本,可以很容易地用肉眼阅读,不用借助程序解析也能够看懂。

请求行与状态行

请求行:请求报文的开始行

GET / HTTP/1.1

  1. 请求方法
  2. 请求目标
  3. 版本号

状态行:响应报文的开始行

HTTP/1.1 200 OK

  1. 版本号
  2. 状态码
  3. 原因

首部字段

key-value 的形式,key 和 value 之间用:分隔,最后用 CRLF 换行表示字段结束

HTTP 头字段非常灵活,不仅可以使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头

  1. 字段名不区分大小写
  2. 字段名里不允许出现空格,可以使用连字符-,但不能使用下划线_
  3. 字段名后面必须紧接着:,不能有空格,而:后的字段值前可以有多个空格;
  4. 字段的顺序是没有意义的,可以任意排列不影响语义
  5. 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

常见首部字段

请求字段

Host:表明要请求的域名,唯一一个 HTTP/1.1 规范里要求必须出现的字段

User-Agent:描述发起 HTTP 请求的客户端的信息。这个信息非常混乱,每个浏览器都自称是“Mozilla”“Chrome”“Safari”,企图使用这个字段来互相“伪装”,导致 User-Agent 变得越来越长,最终变得毫无意义。不过有的比较“诚实”的爬虫会在 User-Agent 里用“spider”标明自己是爬虫

Cookie:携带 Cookie

通用字段

Data:HTTP 报文创建时间

响应字段

Server:告诉客户端当前正在提供 Web 服务的软件名称和版本号

Set-Cookie:告诉浏览器设置 Cookie

状态码

  • 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
  • 2××:成功,报文已经收到并被正确处理;
  • 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
  • 4××:客户端错误,请求报文有误,服务器无法处理;
  • 5××:服务器错误,服务器在处理请求时内部发生了错误。

如何理解请求方法

标准请求方法

目前 HTTP/1.1 规定了八种方法,单词都必须是大写的形式

  1. GET:获取资源,可以理解为读取或者下载数据;
  2. HEAD:获取资源的元信息,即请求头
  3. POST:向资源提交数据,相当于写入或上传数据;
  4. PUT:类似 POST;
  5. DELETE:删除资源;
  6. CONNECT:建立特殊的连接隧道;
  7. OPTIONS:列出可对资源实行的方法;
  8. TRACE:追踪请求 - 响应的传输路径。

扩展方法

虽然 HTTP/1.1 里规定了八种请求方法,但它并没有限制我们只能用这八种方法,这也体现了 HTTP 协议良好的扩展性,我们可以任意添加请求动作,只要请求方和响应方都能理解就行。

安全与幂等

安全

安全是指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。

按照这个定义,只有 GET 和 HEAD 方法是“安全”的,因为它们是“只读”操作

而 POST/PUT/DELETE 操作会修改服务器上的资源,增加或删除数据,所以是“不安全”的。

幂等

意思是多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”。

GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的。

POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT 是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的。

HTTP 优缺点

HTTP 优点

HTTP 是一个灵活可扩展基于 TCP 可靠传输的请求-应答模式的无状态应用层协议

  1. 灵活可扩展:HTTP 协议最初诞生的时候就比较简单,本着开放的精神只规定了报文的基本格式。逐渐增加了请求方法、版本号、状态码、头字段等特性。而 body 也不再限于文本形式的 TXT 或 HTML,而是能够传输图片、音频视频等任意数据。

  2. 可靠传输:HTTP 协议是基于 TCP/IP 的,而 TCP 本身是一个“可靠”的传输协议。不过我们必须正确地理解“可靠”的含义,HTTP 并不能 100% 保证数据一定能够发送到另一端,在网络繁忙、连接质量差等恶劣的环境下,也有可能收发失败。“可靠”只是向使用者提供了一个“承诺”,会在下层用多种手段“尽量”保证数据的完整送达。

  3. 应用层协议:HTTP 凭借着可携带任意头字段和实体数据的报文结构,以及连接控制、缓存代理等方便易用的特性,几乎可以传输任何数据,是一个万能的协议

    HTTP:不要误会,我不是针对 FTP,我是说在座的应用层各位,都是垃圾

  4. 请求 - 应答模式:HTTP 的请求 - 应答模式也恰好契合了传统的 C/S 统架构,此外,请求 - 应答模式也完全符合 RPC(Remote Procedure Call)的工作模式,可以把 HTTP 请求处理封装成远程函数调用,导致了 WebService、RESTful 和 gPRC 等的出现

  5. 无状态:建立连接前两者互不知情,每次收发的报文也都是互相独立的,没有任何的联系。收发报文也不会对客户端或服务器产生任何影响,连接后也不会要求保存任何信息。

HTTP 缺点

  1. 明文传输:报文(准确地说是 header 部分)不使用二进制数据,而是用简单可阅读的文本形式。不需要借助任何外部工具,用浏览器、Wireshark 或者 tcpdump 抓包后,直接用肉眼就可以很容易地查看或者修改。
  2. 不安全:安全有很多的方面,明文只是“机密”方面的一个缺点,在“身份认证”和“完整性校验”这两方面 HTTP 也是欠缺的
  3. 队头阻塞问题:当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。

笔记整理于


罗剑锋:透视HTTP协议

相关文章: