http简介

几种请求方式

表格的内容可以在 图解http这本书里面查看到

方法 解释 作用
post 传输实体主题 经常用,这里不解释
put 传输文件 put方法主要用于上传文件
head 获得报文首部 用于确认url的有效性和资源更新的日期时间等
delete 删除文件 和put相反,用于删除文件,一般 web网站也不使用 这个方法,因为 http/1.1 delete 不带验证机制
options 查询支持的方法 比如 放回 GET,POST,HEAD,OPTIONS
trace 追踪路径 trace不怎么常用,容易引发跨站最终攻击
connect 用隧道协议连接代理 通常在 ssl 中使用,要求 与代理服务器通信时候建立隧道,使用隧道进程tcp通信,主要用 ssl(secure sockets layer 安全套接层)和 tls (transport layer security ,传输层安全) 协议 把通信额内容加密后经过网络隧道传输

http优化方式

优化 解释
持久连接 客户端收到响应不断开连接,继续发送下一个文件
管道化 持久连接文件一个个发,而管道化则是不等待响应,立刻请求下一个文件,【请求数量越多,和持久连接比起来越有优势】

知识图谱

image-20210817214513408

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

DNS

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

于是“域名系统”(Domain Name System)出现了,用有意义的名字来作为 IP 地址的等价替代。设想一下,你是愿意记“95.211.80.227”这样枯燥的数字,还是“nginx.org”这样的词组呢?

在 DNS 中,“域名”(Domain Name)又称为“主机名”(Host),为了更好地标记不同国家或组织的主机,让名字更好记,所以被设计成了一个有层次的结构。

域名用“.”分隔成多个单词,级别从左到右逐级升高,最右边的被称为“顶级域名”。对于顶级域名,可能你随口就能说出几个,例如表示商业公司的“com”、表示教育机构的“edu”,表示国家的“cn”“uk”等,买火车票时的域名还记得吗?是“www.12306.cn”。

传统 DNS 存在哪些问题

缓存问题还是说本地域名解析服务,还是会去权威 DNS 服务器中查找,只不过不是每次都要查找。可以说这还是大导游、大中介。还有一些小导游、小中介,有了请求之后,直接转发给其他运营商去做解析,自己只是外包了出去。

这样的问题是,如果是 A 运营商的客户,访问自己运营商的 DNS 服务器,如果 A 运营商去权威 DNS 服务器查询的话,权威 DNS 服务器知道你是 A 运营商的,就返回给一个部署在 A 运营商的网站地址,这样针对相同运营商的访问,速度就会快很多。

但是 A 运营商偷懒,将解析的请求转发给 B 运营商,B 运营商去权威 DNS 服务器查询的话,权威服务器会误认为,你是 B 运营商的,那就返回给你一个在 B 运营商的网站地址吧,结果客户的每次访问都要跨运营商,速度就会很慢。

域名更新问题

本地 DNS 服务器是由不同地区、不同运营商独立部署的。对域名解析缓存的处理上,实现策略也有区别,有的会偷懒,忽略域名解析结果的 TTL 时间限制,在权威 DNS 服务器解析变更的时候,解析结果在全网生效的周期非常漫长。但是有的时候,在 DNS 的切换中,场景对生效时间要求比较高。

例如双机房部署的时候,跨机房的负载均衡和容灾多使用 DNS 来做。当一个机房出问题之后,需要修改权威 DNS,将域名指向新的 IP 地址,但是如果更新太慢,那很多用户都会出现访问异常。

这就像,有的导游比较勤快、敬业,时时刻刻关注酒店、餐馆、交通的变化,问他的时候,往往会得到最新情况。有的导游懒一些,8 年前背的导游词就没换过,问他的时候,指的路往往就是错的。

URI/URL

有了 TCP/IP 和 DNS,是不是我们就可以任意访问网络上的资源了呢?

还不行,DNS 和 IP 地址只是标记了互联网上的主机,但主机上有那么多文本、图片、页面,到底要找哪一个呢?就像小明管理了一大堆文档,你怎么告诉他是哪个呢?

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

URI 另一个更常用的表现形式是 URL(Uniform Resource Locator), 统一资源定位符,也就是我们俗称的“网址”,它实际上是 URI 的一个子集,不过因为这两者几乎是相同的,差异不大,所以通常不会做严格的区分。

我就拿 Nginx 网站来举例,看一下 URI 是什么样子的。

HTTPS

在 TCP/IP、DNS 和 URI 的“加持”之下,HTTP 协议终于可以自由地穿梭在互联网世界里,顺利地访问任意的网页了,真的是“好生快活”。

SSL 的全称是“Secure Socket Layer”,由网景公司发明,当发展到 3.0 时被标准化,改名为 TLS,即“Transport Layer Security”,但由于历史的原因还是有很多人称之为 SSL/TLS,或者直接简称为 SSL。

HTTPS 就相当于这个比喻中的“火星文”,它的全称是“HTTP over SSL/TLS”,也就是运行在 SSL/TLS 协议上的 HTTP。

注意它的名字,这里是 SSL/TLS,而不是 TCP/IP,它是一个负责加密通信的安全协议,建立在 TCP/IP 之上,所以也是个可靠的传输协议,可以被用作 HTTP 的下层。

因为 HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,其中的“HTTP”和“TCP/IP”我们都已经明白了,只要再了解一下 SSL/TLS,HTTPS 也就能够轻松掌握。

通常认为,如果通信过程具备了四个特性,就可以认为是“安全”的,这四个特性是:机密性、完整性,身份认证和不可否认。

  1. 机密性
  2. 完整性
  3. 身份认证
  4. 不可否认

你可能要问了,既然没有新东西,HTTPS 凭什么就能做到机密性、完整性这些安全特性呢?

秘密就在于 HTTPS 名字里的“S”,它把 HTTP 下层的传输协议由 TCP/IP 换成了 SSL/TLS,由“HTTP over TCP/IP”变成了“HTTP over SSL/TLS”,让 HTTP 运行在了安全的 SSL/TLS 协议上(可参考第 4 讲和第 5 讲),收发报文不再使用 Socket API,而是调用专门的安全接口。

image-20210818133909753

简单来说,SSL 就是通信双方通过非对称加密协商出一个用于对称加密的密钥。

tls过程

,浏览器首先要从 URI 里提取出协议名和域名。因为协议名是“https”,所以浏览器就知道了端口号是默认的 443,它再用 DNS 解析域名,得到目标的 IP 地址,然后就可以使用三次握手与网站建立 TCP 连接了。

在 HTTP 协议里,建立连接后,浏览器会立即发送请求报文。但现在是 HTTPS 协议,它需要再用另外一个“握手”过程,在 TCP 上建立安全连接,之后才是收发 HTTP 报文。

这个“握手”过程与 TCP 有些类似,是 HTTPS 和 TLS 协议里最重要、最核心的部分,懂了它,你就可以自豪地说自己“掌握了 HTTPS”。

http2 优化点

img

头部压缩

首先,HTTP/2 对报文的头部做了一个“大手术”。

通过“进阶篇”的学习你应该知道,HTTP/1 里可以用头字段“Content-Encoding”指定 Body 的编码方式,比如用 gzip 压缩来节约带宽,但报文的另一个组成部分——Header 却被无视了,没有针对它的优化手段。

由于报文 Header 一般会携带“User Agent”“Cookie”“Accept”“Server”等许多固定的头字段,多达几百字节甚至上千字节,但 Body 却经常只有几十字节(比如 GET 请求、204/301/304 响应),成了不折不扣的“大头儿子”。更要命的是,成千上万的请求响应报文里有很多字段值都是重复的,非常浪费,“长尾效应”导致大量带宽消耗在了这些冗余度极高的数据上。

所以,HTTP/2 把“头部压缩”作为性能改进的一个重点,优化的方式你也肯定能想到,还是“压缩”。

不过 HTTP/2 并没有使用传统的压缩算法,而是开发了专门的“HPACK”算法,在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还釆用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。

http2 二进制格式

这样虽然对人不友好,但却大大方便了计算机的解析。原来使用纯文本的时候容易出现多义性,比如大小写、空白字符、回车换行、多字少字等等,程序在处理时必须用复杂的状态机,效率低,还麻烦。

而二进制里只有“0”和“1”,可以严格规定字段大小、顺序、标志位等格式,“对就是对,错就是错”,解析起来没有歧义,实现简单,而且体积小、速度快,做到“内部提效”。

以二进制格式为基础,HTTP/2 就开始了“大刀阔斧”的改革。

  • 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

  • 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

  • header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  • 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

代理

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

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

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

上一讲提到的 CDN,实际上就是一种代理,它代替源站服务器响应客户端的请求,通常扮演着透明代理和反向代理的角色。

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

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

浏览器输入 url发生了什么事情

http长连接特性示意

图里 TCP 关闭连接的“四次挥手”在抓包里没有出现,这是因为 HTTP/1.1 长连接特性,默认不会立即关闭连接。

image-20210817233505309

再简要叙述一下这次最简单的浏览器 HTTP 请求过程:

  1. 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;
  2. 浏览器用 TCP 的三次握手与服务器建立连接;
  3. 浏览器向服务器发送拼好的报文;
  4. 服务器收到报文后处理请求,同样拼好报文再发给浏览器;
  5. 浏览器解析报文,渲染输出页面。

常见的状态码

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

4××类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了。

400 Bad Request”是一个通用的错误码,表示请求报文有错误,但具体是数据格式错误、缺少请求头还是 URI 超长它没有明确说,只是一个笼统的错误,客户端看到 400 只会是“一头雾水”“不知所措”。所以,在开发 Web 应用时应当尽量避免给客户端返回 400,而是要用其他更有明确含义的状态码。

403 Forbidden”实际上不是客户端的请求出错,而是表示服务器禁止访问资源。原因可能多种多样,例如信息敏感、法律禁止等,如果服务器友好一点,可以在 body 里详细说明拒绝请求的原因,不过现实中通常都是直接给一个“闭门羹”。

404 Not Found”可能是我们最常看见也是最不愿意看到的一个状态码,它的原意是资源在本服务器上未找到,所以无法提供给客户端。但现在已经被“用滥了”,只要服务器“不高兴”就可以给出个 404,而我们也无从得知后面到底是真的未找到,还是有什么别的原因,某种程度上它比 403 还要令人讨厌。

500 Internal Server Error”与 400 类似,也是一个通用的错误码,服务器究竟发生了什么错误我们是不知道的。不过对于服务器来说这应该算是好事,通常不应该把服务器内部的详细信息,例如出错的函数调用栈告诉外界。虽然不利于调试,但能够防止黑客的窥探或者分析。

501 Not Implemented”表示客户端请求的功能还不支持,这个错误码比 500 要“温和”一些,和“即将开业,敬请期待”的意思差不多,不过具体什么时候“开业”就不好说了。

502 Bad Gateway”通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的。

503 Service Unavailable”表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503。

tcp和 http 状态理解

第五个特点,HTTP 协议是无状态的。

这个所谓的“状态”应该怎么理解呢?

“状态”其实就是客户端或者服务器里保存的一些数据或者标志,记录了通信过程中的一些变化信息。

你一定知道,TCP 协议是有状态的,一开始处于 CLOSED 状态,连接成功后是 ESTABLISHED 状态,断开连接后是 FIN-WAIT 状态,最后又是 CLOSED 状态。

这些“状态”就需要 TCP 在内部用一些数据结构去维护,可以简单地想象成是个标志量,标记当前所处的状态,例如 0 是 CLOSED,2 是 ESTABLISHED 等等。

再来看 HTTP,那么对比一下 TCP 就看出来了,在整个协议里没有规定任何的“状态”,客户端和服务器永远是处在一种“无知”的状态。建立连接前两者互不知情,每次收发的报文也都是互相独立的,没有任何的联系。收发报文也不会对客户端或服务器产生任何影响,连接后也不会要求保存任何信息。

image-20210817235952295

http优缺点

天的讨论范围仅限于 HTTP/1.1,所说的优点和缺点也仅针对 HTTP/1.1。实际上,专栏后续要讲的 HTTPS 和 HTTP/2 都是对 HTTP/1.1 优点的发挥和缺点的完善。

初次接触 HTTP 的人都会认为,HTTP 协议是很“简单”的,基本的报文格式就是“header+body”,头部信息也是简单的文本格式,用的也都是常见的英文单词,即使不去看 RFC 文档,只靠猜也能猜出个“八九不离十”。

优点

灵活性

“**灵活、易于扩展”**的特性还表现在 HTTP 对“可靠传输”的定义上,它不限制具体的下层协议,不仅可以使用 TCP、UNIX Domain Socket,还可以使用 SSL/TLS,甚至是基于 UDP 的 QUIC,下层可以随意变化,而上层的语义则始终保持稳定。

无状态

“无状态”有什么好处呢?

因为服务器没有“记忆能力”,所以就不需要额外的资源来记录状态信息,不仅实现上会简单一些,而且还能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。

所以,HTTP 协议最好是既“无状态”又“有状态”,不过还真有“鱼和熊掌”两者兼得这样的好事,这就是“小甜饼”Cookie 技术

缺点

明文

HTTP 协议里还有一把优缺点一体的“双刃剑”,就是明文传输

“明文”意思就是协议里的报文(准确地说是 header 部分)不使用二进制数据,而是用简单可阅读的文本形式。

当然,明文的缺点也是一样显而易见,HTTP 报文的所有信息都会暴露在“光天化日之下”,在漫长的传输链路的每一个环节上都毫无隐私可言,不怀好意的人只要侵入了这个链路里的某个设备,简单地“旁路”一下流量,就可以实现对通信的窥视。

你有没有听说过“免费 WiFi 陷阱”之类的新闻呢?

黑客就是利用了 HTTP 明文传输的缺点,在公共场所架设一个 WiFi 热点开始“钓鱼”,诱骗网民上网。一旦你连上了这个 WiFi 热点,所有的流量都会被截获保存,里面如果有银行卡号、网站密码等敏感信息的话那就危险了,黑客拿到了这些数据就可以冒充你为所欲为。

HTTP 协议也不支持“完整性校验”,数据在传输过程中容易被窜改而无法验证真伪。

比如,你收到了一条银行用 HTTP 发来的消息:“小明向你转账一百元”,你无法知道小明是否真的就只转了一百元,也许他转了一千元或者五十元,但被黑客窜改成了一百元,真实情况到底是什么样子 HTTP 协议没有办法给你答案。

虽然银行可以用 MD5、SHA1 等算法给报文加上数字摘要,但还是因为“明文”这个致命缺点,黑客可以连同摘要一同修改,最终还是判断不出报文是否被窜改。

性能

最后我们来谈谈 HTTP 的性能,可以用六个字来概括:“不算差,不够好”。

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

必须要说的是,TCP 的性能是不差的,否则也不会纵横互联网江湖四十余载了,而且它已经被研究的很透,集成在操作系统内核里经过了细致的优化,足以应付大多数的场景。

只可惜如今的江湖已经不是从前的江湖,现在互联网的特点是移动和高并发,不能保证稳定的连接质量,所以在 TCP 层面上 HTTP 协议有时候就会表现的不够好。

其他笔记

[[post/03.基础学科/02_2.408计算机复习/计算机网络复习|计算机网络复习]]

[[post/11.个人总结/计算机网络/计算机网络八股文 |计算机网络八股]] [[post/11.个人总结/计算机网络/tcp ip分层 | tcp ip 分层]]

[[post/11.个人总结/八股文专题【面试八股文】/计算机网络_TCP专题 | tcp专题]]