HTTP协议

什么是URI、什么是HTML、什么是HTTP?

1、URI:即统一资源标识符,作为互联网上资源的唯一身份;

2、HTML(HyperText Transfer Protocol):即超文本标记语言,描述超文本文档;

3、HTTP:即超文本传输协议,用来传输超文本。

HTTP各版本之间的差异(0.9、1.0、1.1、2.0、3.0)

HTTP/1.0 版本在 1996 年正式发布。它在多方面增强了 0.9 版,形式上已经和我们现在的 HTTP 差别不大了,例如:

1、增加了 HEAD、POST 等新方法;

2、增加了响应状态码,标记可能的错误原因;

3、引入了协议版本号概念;

4、引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活;

5、传输的数据不再仅限于文本。

HTTP/1.1 主要的变更点有:

1、增加了 PUT、DELETE 等新的方法;

2、增加了缓存管理和控制;

3、明确了连接管理,允许持久连接;

4、允许响应数据分块(chunked),利于传输大文件;

5、强制要求 Host 头,让互联网主机托管成为可能。

HTTP/2 的制定充分考虑了现今互联网的现状:宽带、移动、不安全,在高度兼容 HTTP/1.1 的同时在性能改善方面做了很大努力,主要的特点有:

1、二进制协议,不再是存文本

2、可发起多个请求,废弃了1.1里的管道

3、使用专用算法压缩头部,减少数据传输量;

4、允许服务器主动向客户端推送数据;

5、增强了安全性,“事实上”要求加密通信

2018 年,互联网标准化组织 IETF 提议将“HTTP over QUIC”更名为“HTTP/3”并获得批准,HTTP/3 正式进入了标准化制订阶段,也许两三年后就会正式发布,到时候我们很可能会跳过 HTTP/2 直接进入 HTTP/3

HTTP 是什么

在这里插入图片描述
1、HTTP 协议是一个“双向协议”。HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范”

2、HTTP 是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。

3、HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。

4、HTTP 传输的是文字、图片、音频、视频等超文本数据。

5、HTTP 是构建互联网的重要基础技术,它没有实体,依赖许多其他的技术来实现,但同时许多技术也都依赖于它

在这里插入图片描述

浏览器

上网就要用到浏览器,常见的浏览器有 Google 的 Chrome、Mozilla 的 Firefox、Apple 的 Safari、Microsoft 的 IE 和 Edge,还有小众的 Opera 以及国内的各种“换壳”的“极速”“安全”浏览器。
在这里插入图片描述

硬件含义就是物理形式或“云”形式的机器,在大多数情况下它可能不是一台服务器,而是利用反向代理、负载均衡等技术组成的庞大集群。但从外界看来,它仍然表现为一台机器,但这个形象是“虚拟的”

软件含义的 Web 服务器可能我们更为关心,它就是提供 Web 服务的应用程序,通常会运行在硬件含义的服务器上。它利用强大的硬件能力响应海量的客户端 HTTP 请求,处理磁盘上的网页、图片等静态文件,或者把请求转发给后面的 Tomcat、Node.js 等业务应用,返回动态的信息。

CDN

CDN,全称是“Content Delivery Network”,翻译过来就是“内容分发网络”。它应用了 HTTP 协议里的缓存和代理技术,代替源站响应客户端的请求。

简单来说,它可以缓存源站的数据,让浏览器的请求不用“千里迢迢”地到达源站服务器,直接在“半路”就可以获取响应。如果 CDN 的调度算法很优秀,更可以找到离用户最近的节点,大幅度缩短响应时间。

爬虫

HTTP 协议并没有规定用户代理后面必须是“真正的人类”,它也完全可以是“机器人”,这些“机器人”的正式名称就叫做“爬虫”(Crawler),实际上是一种可以自动访问 Web 资源的应用程序。

与HTTP相关的协议

TCP/IP

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

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

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

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

DNS

在 DNS 中,“域名”(Domain Name)又称为“主机名”(Host),为了更好地标记不同国家或组织的主机,让名字更好记,所以被设计成了一个有层次的结构。域名用“.”分隔成多个单词,级别从左到右逐级升高,最右边的被称为“顶级域名”。对于顶级域名,可能你随口就能说出几个,例如表示商业公司的“com”、表示教育机构的“edu”,表示国家的“cn”“uk”等,买火车票时的域名还记得吗?是“www.12306.cn”。

URI/URL

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

URI 主要有三个基本的部分构成

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

1、协议名:即访问该资源应当使用的协议,在这里是“http”;

2、主机名:即互联网上主机的标记,可以是域名或 IP 地址,在这里是“nginx.org”;

3、路径:即资源在主机上的位置,使用“/”分隔多级目录,在这里是“/en/download.html”。

HTTPS

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

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

SSL 使用了许多密码学最先进的研究成果,综合了对称加密、非对称加密、摘要算法、数字签名、数字证书等技术,能够在不安全的环境中为通信的双方创建出一个秘密的、安全的传输通道,为 HTTP 套上一副坚固的盔甲。

代理

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

1、匿名代理:完全“隐匿”了被代理的机器,外界看到的只是代理服务器;

2、透明代理:顾名思义,它在传输过程中是“透明开放”的,外界既知道代理,也知道客户端;

3、正向代理:靠近客户端,代表客户端向服务器发送请求;

4、反向代理:靠近服务器端,代表服务器响应客户端的请求;

由于代理在传输过程中插入了一个“中间层”,所以可以在这个环节做很多有意思的事情,比如:
1、负载均衡:把访问请求均匀分散到多台机器,实现访问集群化;

2、内容缓存:暂存上下行的数据,减轻后端的压力;

3、安全防护:隐匿 IP, 使用 WAF 等工具抵御网络攻击,保护被代理的机器;

4、数据处理:提供压缩、加密等额外的功能。关于 HTTP 的代理还有一个特殊的“代理协议”(proxy protocol),它由知名的代理软件 HAProxy 制订,但并不是 RFC 标准,我也会在之后的课程里专门讲解

1、TCP/IP 是网络世界最常用的协议,HTTP 通常运行在 TCP/IP 提供的可靠传输基础上;

2、DNS 域名是 IP 地址的等价替代,需要用域名解析实现到 IP 地址的映射;

3、URI 是用来标记互联网上资源的一个名字,由“协议名 + 主机名 + 路径”构成,俗称 URL;

4、HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,为 HTTP 套了一个安全的外壳;

5、代理是 HTTP 传输过程中的“中转站”,可以实现缓存加速、负载均衡等功能

TCP/IP 网络分层模型

链接层负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备,所以有时候也叫 MAC 层。

网际层”或者“网络互连层”(internet layer),IP 协议就处在这一层。因为 IP 协议定义了“IP 地址”的概念,所以就可以在“链接层”的基础上,用 IP 地址取代 MAC 地址,把许许多多的局域网、广域网连接成一个虚拟的巨大网络,在这个网络里找设备时只要把 IP 地址再“翻译”成 MAC 地址就可以了。

传输层这个层次协议的职责是保证数据在 IP 地址标记的两点之间“可靠”地传输,是 TCP 协议工作的层次,另外还有它的一个“小伙伴”UDP。

TCP 是一个有状态的协议,需要先与对方建立连接然后才能发送数据,而且保证数据不丢失不重复。而 UDP 则比较简单,它无状态,不用事先建立连接就可以任意发送数据,但不保证数据一定会发到对方。两个协议的另一个重要区别在于数据的形式。TCP 的数据是连续的“字节流”,有先后顺序,而 UDP 则是分散的小数据包,是顺序发,乱序收

应用层”(application layer),由于下面的三层把基础打得非常好,所以在这一层就“百花齐放”了,有各种面向具体应用的协议。例如 Telnet、SSH、FTP、SMTP 等等,当然还有我们的 HTTP。

OSI 网络分层模型

OSI,全称是“开放式系统互联通信参考模型”(Open System Interconnection Reference Model)。

第一层:物理层,网络的物理形式,例如电缆、光纤、网卡、集线器等等;
第二层:数据链路层,它基本相当于 TCP/IP 的链接层;
第三层:网络层,相当于 TCP/IP 里的网际层;
第四层:传输层,相当于 TCP/IP 里的传输层;
第五层:会话层,维护网络中的连接状态,即保持会话和同步;
第六层:表示层,把数据转换为合适、可理解的语法和语义;
第七层:应用层,面向具体的应用传输数据。

域名

域名的形式

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

看一下极客时间的域名“time.geekbang.org”,这里的“org”就是顶级域名,“geekbang”是二级域名,“time”则是主机名。使用这个域名,DNS 就会把它转换成相应的 IP 地址,你就可以访问极客时间的网站了。

域名的解析

DNS 的核心系统是一个三层的树状、分布式服务,基本对应域名的结构:

1、根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等

2、顶级域名服务器的 IP 地址;顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址;

3、权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com 权威域名服务器可以返回 www.apple.com 的 IP 地址。

在这里根域名服务器是关键,它必须是众所周知的,否则下面的各级服务器就无从谈起了。目前全世界共有 13 组根域名服务器,又有数百台的镜像,保证一定能够被访问到。

例如,你要访问“www.apple.com”,就要进行下面的三次查询:

1、访问根域名服务器,它会告诉你“com”顶级域名服务器的地址;

2、访问“com”顶级域名服务器,它再告诉你“apple.com”域名服务器的地址;

3、最后访问“apple.com”域名服务器,就得到了“www.apple.com”的地址。

虽然核心的 DNS 系统遍布全球,服务能力很强也很稳定,但如果全世界的网民都往这个系统里挤,即使不挤瘫痪了,访问速度也会很慢。所以在核心 DNS 系统之外,还有两种手段用来减轻域名解析的压力,并且能够更快地获取结果,基本思路就是**“缓存”**

输入一个网址,回车,后面究竟发生了什么?

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

1、浏览器从地址栏的输入中通过DNS域名解析获得服务器的 IP 地址和端口号;

2、浏览器用 TCP 的三次握手与服务器建立连接;

3、浏览器向服务器发送拼好的报文;

4、服务器收到报文后处理请求,同样拼好报文再发给浏览器;

5、浏览器解析报文,渲染输出页面。

HTTP报文是什么样子的

报文结构
在这里插入图片描述
HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:

1、起始行(start line):描述请求或响应的基本信息;

2、头部字段集合(header):使用 key-value 形式更详细地说明报文;

3、消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。
在这里插入图片描述
请求行

了解了 HTTP 报文的基本结构后,我们来看看请求报文里的起始行也就是请求行(request line),它简要地描述了客户端想要如何操作服务器端的资源。

请求行由三部分构成:

1、请求方法:是一个动词,如 GET/POST,表示对资源的操作;

2、请求目标:通常是一个 URI,标记了请求方法要操作的资源;

3、版本号:表示报文使用的 HTTP 协议版本。
在这里插入图片描述
状态行

看完了请求行,我们再看响应报文里的起始行,在这里它不叫“响应行”,而是叫“状态行”(status line),意思是服务器响应的状态。

1、版本号:表示报文使用的 HTTP 协议版本;

2、状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;

3、原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。

在这里插入图片描述
头部字段

在这里插入图片描述
HTTP 头字段非常灵活,不仅可以使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头,这就给 HTTP 协议带来了无限的扩展可能。

不过使用头字段需要注意下面几点:
1、字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;

2、字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;

3、字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;

4、字段的顺序是没有意义的,可以任意排列不影响语义;

5、字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

常用头字段

HTTP 协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类:

1、通用字段:在请求头和响应头里都可以出现;

2、请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;

3、响应字段:仅能出现在响应头里,补充说明响应报文的信息;

4、实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。

如何理解请求方法?

标准请求方法

目前 HTTP/1.1 规定了八种方法,单词都必须是大写的形式,我先简单地列把它们列出来,后面再详细讲解。

1、GET:获取资源,可以理解为读取或者下载数据;

2、HEAD:获取资源的元信息;

3、POST:向资源提交数据,相当于写入或上传数据;

4、PUT:类似 POST;

5、DELETE:删除资源;

6、CONNECT:建立特殊的连接隧道;

7、OPTIONS:列出可对资源实行的方法;

8、TRACE:追踪请求 - 响应的传输路径。

状态码

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

1××

1××类状态码属于提示信息,是协议处理的中间状态,实际能够用到的时候很少。

我们偶尔能够见到的是“101 Switching Protocols”。它的意思是客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。

2××

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

“200 OK”是最常见的成功状态码,表示一切正常,服务器如客户端所期望的那样返回了处理结果,如果是非 HEAD 请求,通常在响应头后都会有 body 数据。

“204 No Content”是另一个很常见的成功状态码,它的含义与“200 OK”基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的。

“206 Partial Content”是 HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。

状态码 206 通常还会伴随着头字段“Content-Range”,表示响应报文里 body 数据的具体范围,供客户端确认,例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计 2000 个字节的前 100 个字节。

3××
类状态码表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源,也就是通常所说的“重定向”,包括著名的 301、302 跳转。“301 Moved Permanently”俗称“永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问。与它类似的是“302 Found”,曾经的描述短语是“Moved Temporarily”,俗称“临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问。301 和 302 都会在响应头里使用字段 Location 指明后续要跳转的 URI,最终的效果很相似,浏览器都会重定向到新的 URI。两者的根本区别在于语义,一个是“永久”,一个是“临时”,所以在场景、用法上差距很大。

4××

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

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

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

“404 Not Found”可能是我们最常看见也是最不愿意看到的一个状态码,它的原意是资源在本服务器上未找到,所以无法提供给客户端。但现在已经被“用滥了”,只要服务器“不高兴”就可以给出个 404,而我们也无从得知后面到底是真的未找到,还是有什么别的原因,某种程度上它比 403 还要令人讨厌。
4××里剩下的一些代码较明确地说明了错误的原因,都很好理解,开发中常用的有:

405 Method Not Allowed:不允许使用某些方法操作资源,例如不允许 POST 只能 GET;

406 Not Acceptable:资源无法满足客户端请求的条件,例如请求中文但只有英文;

408 Request Timeout:请求超时,服务器等待了过长的时间;

409 Conflict:多个请求发生了冲突,可以理解为多线程并发时的竞态;

413 Request Entity Too Large:请求报文里的 body 太大;

414 Request-URI Too Long:请求行里的 URI 太大;

429 Too Many Requests:客户端发送了太多的请求,通常是由于服务器的限连策略;

431 Request Header Fields Too Large:请求头某个字段或总体太大;

5××

5××类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”。

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

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

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

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

503 是一个“临时”的状态,很可能过几秒钟后服务器就不那么忙了,可以继续提供服务,所以 503 响应报文里通常还会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求。

HTTP有哪些特点?

灵活可扩展

HTTP 协议最初诞生的时候就比较简单,本着开放的精神只规定了报文的基本格式,比如用空格分隔单词,用换行分隔字段,“header+body”等,报文里的各个组成部分都没有做严格的语法语义限制,可以由开发者任意定制。

可靠传输

因为 HTTP 协议是基于 TCP/IP 的,而 TCP 本身是一个“可靠”的传输协议,所以 HTTP 自然也就继承了这个特性,能够在请求方和应答方之间“可靠”地传输数据。

应用层协议

在 TCP/IP 诞生后的几十年里,虽然出现了许多的应用层协议,但它们都仅关注很小的应用领域,局限在很少的应用场景。例如 FTP 只能传输文件、SMTP 只能发送邮件、SSH 只能远程登录等,在通用的数据传输方面“完全不能打”

请求 - 应答

这个请求 - 应答模式是 HTTP 协议最根本的通信模型,通俗来讲就是“一发一收”“有来有去”,就像是写代码时的函数调用,只要填好请求头里的字段,“调用”后就会收到答复。

无状态

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

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

总结

1、HTTP 是灵活可扩展的,可以任意添加头字段实现任意功能;

2、HTTP 是可靠传输协议,基于 TCP/IP 协议“尽量”保证数据的送达;

3、HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据;

4、HTTP 使用了请求 - 应答模式,客户端主动发起请求,服务器被动回复请求;

5、HTTP 本质上是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。

HTTP有哪些优点?又有哪些缺点?

1、简单、灵活、易于扩展

HTTP 协议里的请求方法、URI、状态码、原因短语、头字段等每一个核心组成要素都没有被“写死”,允许开发者任意定制、扩充或解释,给予了浏览器和服务器最大程度的信任和自由,也正好符合了互联网“自由与平等”的精神——缺什么功能自己加个字段或者错误码什么的补上就是了。

2、应用广泛、环境成熟

随着互联网特别是移动互联网的普及,HTTP 的触角已经延伸到了世界的每一个角落:从简单的 Web 页面到复杂的 JSON、XML 数据,从台式机上的浏览器到手机上的各种 APP,从看新闻、泡论坛到购物、理财、“吃鸡”,你很难找到一个没有使用 HTTP 的地方。不仅在应用领域,在开发领域 HTTP 协议也得到了广泛的支持。它并不限定某种编程语言或者操作系统,所以天然具有“跨语言、跨平台”的优越性。而且,因为本身的简单特性很容易实现,所以几乎所有的编程语言都有 HTTP 调用库和外围的开发测试工具,这一点我觉得就不用再举例了吧,你可能比我更熟悉。HTTP 广泛应用的背后还有许多硬件基础设施支持,各个互联网公司和传统行业公司都不遗余力地“触网”,购买服务器开办网站,建设数据中心、CDN 和高速光纤,持续地优化上网体验,让 HTTP 运行的越来越顺畅。

3、无状态

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

因为服务器没有“记忆能力”,所以就不需要额外的资源来记录状态信息,不仅实现上会简单一些,而且还能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。而且,“无状态”也表示服务器都是相同的,没有“状态”的差异,所以可以很容易地组成集群,让负载均衡把请求转发到任意一台服务器,不会因为状态不一致导致处理出错,使用“堆机器”的“笨办法”轻松实现高并发高可用

那么,“无状态”又有什么坏处呢?

既然服务器没有“记忆能力”,它就无法支持需要连续多个步骤的“事务”操作。例如电商购物,首先要登录,然后添加购物车,再下单、结算、支付,这一系列操作都需要知道用户的身份才行,但“无状态”服务器是不知道这些请求是相互关联的,每次都得问一遍身份信息,不仅麻烦,而且还增加了不必要的数据传输量。

4、明文传输

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

对比 TCP、UDP 这样的二进制协议,它的优点显而易见,不需要借助任何外部工具,用浏览器、Wireshark 或者 tcpdump 抓包后,直接用肉眼就可以很容易地查看或者修改,为我们的开发调试工作带来极大的便利。

5、不安全

总结:

1、HTTP 最大的优点是简单、灵活和易于扩展;

2、HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施;

3、HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”;

4、HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听;

5、HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改;

6、HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间

HTTP的实体数据

数据类型与编码

在 TCP/IP 协议栈里,传输数据基本上都是“header+body”的格式。但 TCP、UDP 因为是传输层的协议,它们不会关心 body 数据是什么,只要把数据发送到对方就算是完成了任务。

而 HTTP 协议则不同,它是应用层的协议,数据到达之后工作只能说是完成了一半,还必须要告诉上层应用这是什么数据才行,否则上层应用就会“不知所措”。

HTTP 里经常遇到的几个类别:

1、text:即文本格式的可读数据,我们最熟悉的应该就是 text/html 了,表示超文本文档,此外还有纯文本 text/plain、样式表 text/css 等。

2、image:即图像文件,有 image/gif、image/jpeg、image/png 等。audio/video:音频和视频数据,例如 audio/mpeg、video/mp4 等。

3、application:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释。常见的有 application/json,

4、application/javascript、application/pdf 等,另外,如果实在是不知道数据是什么类型,像刚才说的“黑盒”,就会是 application/octet-stream,即不透明的二进制数据。

MIME type 还不够,因为 HTTP 在传输时为了节约带宽,有时候还会压缩数据,为了不要让浏览器继续“猜”,还需要有一个“Encoding type”,告诉数据是用的什么编码格式,这样对方才能正确解压缩,还原出原始的数据。

1、gzip:GNU zip 压缩格式,也是互联网上最流行的压缩格式;

2、deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip;

3、br:一种专门为 HTTP 优化的新压缩算法(Brotli)。

数据类型使用的头字段
在这里插入图片描述
Accept 字段标记的是客户端可理解的 MIME type,可以用“,”做分隔符列出多个类型,让服务器有更多的选择余地,例如下面的这个头:

Accept: text/html,application/xml,image/webp,image/png

相应的,服务器会在响应报文里用头字段 Content-Type 告诉实体数据的真实类型

Content-Type: text/html
Content-Type: image/png

Accept-Encoding 字段标记的是客户端支持的压缩格式,例如上面说的 gzip、deflate 等,同样也可以用“,”列出多个,服务器可以选择其中一种来压缩数据,实际使用的压缩格式放在响应头字段 Content-Encoding 里。

Accept-Encoding: gzip, deflate, br
Content-Encoding: gzip

语言类型与编码

en 表示任意的英语,en-US 表示美式英语,en-GB 表示英式英语,而 zh-CN 就表示我们最常使用的汉语。关于自然语言的计算机处理还有一个更麻烦的东西叫做“字符集”。在计算机发展的早期,各个国家和地区的人们“各自为政”,发明了许多字符编码方式来处理文字,比如英语世界用的 ASCII、汉语世界用的 GBK、BIG5,日语世界用的 Shift_JIS 等。同样的一段文字,用一种编码显示正常,换另一种编码后可能就会变得一团糟。所以后来就出现了 Unicode 和 UTF-8,把世界上所有的语言都容纳在一种编码方案里,遵循 UTF-8 字符编码方式的 Unicode 字符集也成为了互联网上的标准字符集。

语言类型使用的头字段

Accept-Language: zh-CN, zh, en

相应的,服务器应该在响应报文里用头字段 Content-Language 告诉客户端实体数据使用的实际语言类型:

Content-Language: zh-CN

总结:

1、数据类型表示实体数据的内容是什么,使用的是 MIME type,相关的头字段是 Accept 和 Content-Type;

2、数据编码表示实体数据的压缩方式,相关的头字段是 Accept-Encoding 和 Content-Encoding;

3、语言类型表示实体数据的自然语言,相关的头字段是 Accept-Language 和 Content-Language;

4、字符集表示实体数据的编码方式,相关的头字段是 Accept-Charset 和 Content-Type;

5、客户端需要在请求头里使用 Accept 等头字段与服务器进行“内容协商”,要求服务器返回最合适的数据;

6、Accept 等头字段可以用“,”顺序列出多个可能的选项,还可以用“;q=”参数来精确指定权重。

HTTP怎么传输一个大文件?

数据压缩

通常浏览器在发送请求时都会带着“Accept-Encoding”头字段,里面是浏览器支持的压缩格式列表,例如 gzip、deflate、br 等,这样服务器就可以从中选择一种压缩算法,放进“Content-Encoding”响应头里,再把原数据压缩后发给浏览器

不过数据压缩在处理文本的时候效果还是很好的,所以各大网站的服务器都会使用这个手段作为“保底”。例如,在 Nginx 里就会使用“gzip on”指令,启用对“text/html”的压缩。

分块传输

这种“化整为零”的思路在 HTTP 协议里就是“chunked”分块传输编码,在响应报文里用头字段“Transfer-Encoding: chunked”来表示,意思是报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送。

分块传输的编码规则,其实也很简单,同样采用了明文的方式,很类似响应头。

1、每个分块包含两个部分,长度头和数据块;

2、长度头是以 CRLF(回车换行,即\r\n)结尾的一行明文,用 16 进制数字表示长度;

3、数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;

4、最后用一个长度为 0 的块表示结束,即“0\r\n\r\n”。

在这里插入图片描述

范围请求

HTTP 协议为了满足这样的需求,提出了“范围请求”(range requests)的概念,允许客户端在请求头里使用专用字段来表示只获取文件的一部分,相当于是客户端的“化整为零”。范围请求不是 Web 服务器必备的功能,可以实现也可以不实现,所以服务器必须在响应头里使用字段“Accept-Ranges: bytes”明确告知客户端:“我是支持范围请求的”。如果不支持的话该怎么办呢?服务器可以发送“Accept-Ranges: none”,或者干脆不发送“Accept-Ranges”字段,这样客户端就认为服务器没有实现范围请求功能,只能老老实实地收发整块文件了。请求头 Range 是 HTTP 范围请求的专用字段,格式是“bytes=x-y”,其中的 x 和 y 是以字节为单位的数据范围。

Range 的格式也很灵活,起点 x 和终点 y 可以省略,能够很方便地表示正数或者倒数的范围。假设文件是 100 个字节,那么:

“0-”表示从文档起点到文档终点,相当于“0-99”,即整个文件;

“10-”是从第 10 个字节开始到文档末尾,相当于“10-99”;

“-1”是文档的最后一个字节,相当于“99-99”;

“-10”是从文档末尾倒数 10 个字节,相当于“90-99”。

第一,它必须检查范围是否合法,比如文件只有 100 个字节,但请求“200-300”,这就是范围越界了。服务器就会返回状态码 416,意思是“你的范围请求有误,我无法处理,请再检查一下”。

第二,如果范围正确,服务器就可以根据 Range 头计算偏移量,读取文件的片段了,返回状态码“206 Partial Content”,和 200 的意思差不多,但表示 body 只是原数据的一部分。

第三,服务器要添加一个响应头字段 Content-Range,告诉片段的实际偏移量和资源的总大小,格式是“bytes x-y/length”,与 Range 头区别在没有“=”,范围后多了总长度。例如,对于“0-10”的范围请求,值就是“bytes 0-10/100”。

不仅看视频的拖拽进度需要范围请求,常用的下载工具里的多段下载、断点续传也是基于它实现的,要点是:

先发个 HEAD,看服务器是否支持范围请求,同时获取文件的大小;

开 N 个线程,每个线程使用 Range 字段划分出各自负责下载的片段,发请求传输数据;

下载意外中断也不怕,不必重头再来一遍,只要根据上次的下载记录,用 Range 请求剩下的那一部分就可以了。

多段数据

这种情况需要使用一种特殊的 MIME 类型:“multipart/byteranges”,表示报文的 body 是由多段字节序列组成的,并且还要用一个参数“boundary=xxx”给出段之间的分隔标记。

多段数据的格式与分块传输也比较类似,但它需要用分隔标记 boundary 来区分不同的片段,可以通过图来对比一下。

总结:

1、压缩 HTML 等文本文件是传输大文件最基本的方法;

2、分块传输可以流式收发数据,节约内存和带宽,使用响应头字段“Transfer-Encoding: chunked”来表示,分块的格式是 16 进制长度头 + 数据块;

3、范围请求可以只获取部分数据,即“分块请求”,实现视频拖拽或者断点续传,使用请求头字段“Range”和响应头字段“Content-Range”,响应状态码必须是 206;

4、也可以一次请求多个范围,这时候响应报文的数据类型是“multipart/byteranges”,body 里的多个部分会用 boundary 字符串分隔。

HTTP连接管理

长连接

针对短连接暴露出的缺点,HTTP 协议就提出了“长连接”的通信方式,也叫“持久连接”(persistent connections)、“连接保活”(keep alive)、“连接复用”(connection reuse)。其实解决办法也很简单,用的就是“成本均摊”的思路,既然 TCP 的连接和关闭非常耗时间,那么就把这个时间成本由原来的一个“请求 - 应答”均摊到多个“请求 - 应答”上。

连接相关的头字段

由于长连接对性能的改善效果非常显著,所以在 HTTP/1.1 中的连接都会默认启用长连接。不需要用什么特殊的头字段指定,只要向服务器发送了第一次请求,后续的请求都会重复利用第一次打开的 TCP 连接,也就是长连接,在这个连接上收发数据

当然,我们也可以在请求头里明确地要求使用长连接机制,使用的字段是 Connection,值是“keep-alive”。

服务器端通常不会主动关闭连接,但也可以使用一些策略。拿 Nginx 来举例,它有两种方式:

1、使用“keepalive_timeout”指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。

2、使用“keepalive_requests”指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。

队头阻塞

“队头阻塞”与短连接和长连接无关,而是由 HTTP 基本的“请求 - 应答”模型所导致的。

因为 HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求被最优先处理。

如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本。

性能优化

并发连接”(concurrent connections),也就是同时对一个域名发起多个长连接,用数量来解决质量的问题。但这种方式也存在缺陷。如果每个客户端都想自己快,建立很多个连接,用户数×并发数就会是个天文数字。服务器的资源根本就扛不住,或者被服务器认为是恶意攻击,反而会造成“拒绝服务”。

就是“域名分片”(domain sharding)技术,还是用数量来解决质量的思路。

总结
1、早期的 HTTP 协议使用短连接,收到响应后就立即关闭连接,效率很低;

2、HTTP/1.1 默认启用长连接,在一个连接上收发多个请求响应,提高了传输效率;

3、服务器会发送“Connection: keep-alive”字段表示启用了长连接;

4、报文头里如果有“Connection: close”就意味着长连接即将关闭;

5、过多的长连接会占用服务器资源,所以服务器会用一些策略有选择地关闭长连接;

6、“队头阻塞”问题会导致性能下降,可以用“并发连接”和“域名分片”技术缓解。

HTTP重定向和跳转

重定向的过程

301 是“永久重定向”,302 是“临时重定向”,浏览器收到这两个状态码就会跳转到新的 URI。

总结
1、重定向是服务器发起的跳转,要求客户端改用新的 URI 重新发送请求,通常会自动进行,用户是无感知的;

2、301/302 是最常用的重定向状态码,分别是“永久重定向”和“临时重定向”;

3、响应头字段 Location 指示了要跳转的 URI,可以用绝对或相对的形式;

4、重定向可以把一个 URI 指向另一个 URI,也可以把多个 URI 指向同一个 URI,用途很多;

5、使用重定向时需要当心性能损耗,还要避免出现循环跳转。

HTTP的Cookie机制

Cookie 的工作过程

这要用到两个字段:响应头字段 Set-Cookie 和请求头字段 Cookie。

当用户通过浏览器第一次访问服务器的时候,服务器肯定是不知道他的身份的。所以,就要创建一个独特的身份标识数据,格式是“key=value”,然后放进 Set-Cookie 字段里,随着响应报文一同发给浏览器。浏览器收到响应报文,看到里面有 Set-Cookie,知道这是服务器给的身份标识,于是就保存起来,下次再请求的时候就自动把这个值放进 Cookie 字段里发给服务器。

因为第二次请求里面有了 Cookie 字段,服务器就知道这个用户不是新人,之前来过,就可以拿出 Cookie 里的值,识别出用户的身份,然后提供个性化的服务。不过因为服务器的“记忆能力”实在是太差,一张小纸条经常不够用。所以,服务器有时会在响应头里添加多个 Set-Cookie,存储多个“key=value”。但浏览器这边发送时不需要用多个 Cookie 字段,只要在一行里用“;”隔开就行

Cookie 的属性

**“Expires”**俗称“过期时间”,用的是绝对时间点,可以理解为“截止日期”(deadline)。

**“Max-Age”**用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。Expires 和 Max-Age 可以同时出现,两者的失效时间可以一致,也可以不一致,但浏览器会优先采用 Max-Age 计算失效期。比如在这个例子里,Expires 标记的过期时间是“GMT 2019 年 6 月 7 号 8 点 19 分”,而 Max-Age 则只有 10 秒,如果现在是 6 月 6 号零点,那么 Cookie 的实际有效期就是“6 月 6 号零点过 10 秒”。

设置 Cookie 的作用域,让浏览器仅发送给特定的服务器和 URI,避免被其他网站盗用。作用域的设置比较简单,

“Domain”和“Path”指定了 Cookie 所属的域名和路径,浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。

Cookie 的安全性

性“HttpOnly”会告诉浏览器,此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问,浏览器的 JS 引擎就会禁用 document.cookie 等一切相关的 API,脚本攻击也就无从谈起了。

另一个属性“SameSite”可以防范“跨站请求伪造”(XSRF)攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。

还有一个属性叫“Secure”,表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送。但 Cookie 本身不是加密的,浏览器里还是以明文的形式存在。

Cookie 的应用

Cookie 最基本的一个用途就是身份识别,保存用户的登录信息,实现会话事务。

Cookie 的另一个常见用途是广告跟踪。

总结

1、Cookie 是服务器委托浏览器存储的一些数据,让服务器有了“记忆能力”;

2、响应报文使用 Set-Cookie 字段发送“key=value”形式的 Cookie 值;

3、请求报文里用 Cookie 字段发送多个 Cookie 值;

4、为了保护 Cookie,还要给它设置有效期、作用域等属性,常用的有 Max-Age、Expires、Domain、HttpOnly 等;

5、Cookie 最基本的用途是身份识别,实现有状态的会话事务。

HTTP的缓存控制

基于请求 - 应答”模式的特点,可以大致分为客户端缓存和服务器端缓存,因为服务器端缓存经常与代理服务“混搭”在一起,所以今天我先讲客户端——也就是浏览器的缓存。

服务器的缓存控制

1、浏览器发现缓存无数据,于是发送请求,向服务器获取资源;

2、服务器响应请求,返回资源,同时标记资源的有效期;

3、浏览器缓存资源,等待下次重用。

服务器标记资源有效期使用的头字段是“Cache-Control”,里面的值“max-age=30”就是资源的有效时间,相当于告诉浏览器,“这个页面只能缓存 30 秒,之后就算是过期,不能用。”

“max-age”是 HTTP 缓存控制最常用的属性,此外在响应报文里还可以用其他的属性来更精确地指示浏览器应该如何使用缓存:

no-store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;

no-cache:它的字面含义容易与 no-store 搞混,实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本;

must-revalidate:又是一个和 no-cache 相似的词,它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证。

客户端的缓存控制

不止服务器可以发“Cache-Control”头,浏览器也可以发“Cache-Control”,也就是说请求 - 应答的双方都可以用这个字段进行缓存控制,互相协商缓存的使用策略。

条件请求

所以 HTTP 协议就定义了一系列“If”开头的“条件请求”字段,专门用来检查验证资源是否过期,把两个请求才能完成的工作合并在一个请求里做。而且,验证的责任也交给服务器,浏览器只需“坐享其成”。条件请求一共有 5 个头字段,我们最常用的是“if-Modified-Since”和“If-None-Match”这两个。需要第一次的响应报文预先提供“Last-modified”和“ETag”,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。如果资源没有变,服务器就回应一个“304 Not Modified”,表示缓存依然有效,浏览器就可以更新一下有效期,然后放心大胆地使用缓存了。

总结

1、缓存是优化系统性能的重要手段,HTTP 传输的每一个环节中都可以有缓存;

2、服务器使用“Cache-Control”设置缓存策略,常用的是“max-age”,表示资源的有效期;

3、浏览器收到数据就会存入缓存,如果没过期就可以直接使用,过期就要去服务器验证是否仍然可用;

4、验证资源是否失效需要使用“条件请求”,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以复用缓存里的资源;

5、验证资源是否被修改的条件有两个:“Last-modified”和“ETag”,需要服务器预先在响应报文里设置,搭配条件请求使用;

6、浏览器也可以发送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新数据。

HTTP的代理服务

代理服务”就是指服务本身不生产内容,而是处于中间位置转发上下游的请求和响应,具有双重身份:面向下游的用户时,表现为服务器,代表源服务器响应客户端的请求;而面向上游的源服务器时,又表现为客户端,代表客户端发送请求。

代理最基本的一个功能是负载均衡。因为在面向客户端时屏蔽了源服务器,客户端看到的只是代理服务器,源服务器究竟有多少台、是哪些 IP 地址都不知道。于是代理服务器就可以掌握请求分发的“大权”,决定由后面的哪台服务器来响应请求。

在负载均衡的同时,代理服务还可以执行更多的功能,比如:

1、健康检查:使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用;

2、安全防护:保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载;

3、加密卸载:对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本;

4、数据过滤:拦截上下行的数据,任意指定策略修改请求或者响应;

5、内容缓存:暂存、复用服务器响应,这个与第 20 讲密切相关,我们稍后再说

总结

HTTP 代理就是客户端和服务器通信链路中的一个中间环节,为两端提供“代理服务”;代理处于中间层,为 HTTP 处理增加了更多的灵活性,可以实现负载均衡、安全防护、数据过滤等功能;代理服务器需要使用字段“Via”标记自己的身份,多个代理会形成一个列表;如果想要知道客户端的真实 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”;专门的“代理协议”可以在不改动原始报文的情况下传递客户端的真实 IP。

HTTP缓存代理服务

1、计算机领域里最常用的性能优化手段是“时空转换”,也就是“时间换空间”或者“空间换时间”,HTTP 缓存属于后者;

2、缓存代理是增加了缓存功能的代理服务,缓存源服务器的数据,分发给下游的客户端;

3、“Cache-Control”字段也可以控制缓存代理,常用的有“private”“s-maxage”“no-transform”等,同样必须配合“Last-modified”“ETag”等字段才能使用;

4、缓存代理有时候也会带来负面影响,缓存不良数据,需要及时刷新或删除

HTTPS是什么?SSL/TLS又是什么?

为什么要有 HTTPS?

简单的回答是“因为 HTTP 不安全”。

什么是安全?

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

机密性(Secrecy/Confidentiality)是指对数据的“保密”,只能由可信的人访问,对其他人是不可见的“秘密”,简单来说就是不能让不相关的人看到不该看的东西。

**完整性(Integrity,也叫一致性)**是指数据在传输过程中没有被篡改,不多也不少,“完完整整”地保持着原状。
机密性虽然可以让数据成为“秘密”,但不能防止黑客对数据的修改,黑客可以替换数据,调整数据的顺序,或者增加、删除部分数据,破坏通信过程。

**身份认证(Authentication)**是指确认对方的真实身份,也就是“证明你真的是你”,保证消息只能发送给可信的人。

如果通信时另一方是假冒的网站,那么数据再保密也没有用,黑客完全可以使用冒充的身份“套”出各种信息,加密和没加密一样

不可否认(Non-repudiation/Undeniable),也叫不可抵赖,意思是不能否认已经发生过的行为,不能“说话不算数”“耍赖皮”。

什么是 HTTPS?

新的协议名“https”,默认端口号 443,至于其他的什么请求 - 应答模式、报文结构、请求方法、URI、头字段、连接管理等等都完全沿用 HTTP,没有任何新的东西。

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

SSL 即安全套接层(Secure Sockets Layer),在 OSI 模型中处于第 5 层(会话层),由网景公司于 1994 年发明,有 v2 和 v3 两个版本,而 v1 因为有严重的缺陷从未公开过。

SSL 发展到 v3 时已经证明了它自身是一个非常好的安全通信协议,于是互联网工程组 IETF 在 1999 年把它改名为 TLS(传输层安全,Transport Layer Security),正式标准化,版本号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1。

TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。

总结
1、因为 HTTP 是明文传输,所以不安全,容易被黑客窃听或篡改;

2、通信安全必须同时具备机密性、完整性、身份认证和不可否认这四个特性;

3、HTTPS 的语法、语义仍然是 HTTP,但把下层的协议由 TCP/IP 换成了 SSL/TLS;

4、SSL/TLS 是信息安全领域中的权威标准,采用多种先进的加密技术保证通信安全;

5、OpenSSL 是著名的开源密码学工具包,是 SSL/TLS 的具体实现。

对称加密和非对称加密

现机密性最常用的手段是“加密”(encrypt),就是把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊“钥匙”的人才能再转换出原始文本。这里的“钥匙”就叫做**“密钥”(key),加密前的消息叫“明文”(plain text/clear text),加密后的乱码叫“密文”(cipher text),使用密钥还原明文的过程叫“解密”(decrypt)**,是加密的反操作,加密解密的操作过程就是“加密算法”

按照密钥的使用方式,加密可以分为两大类:对称加密和非对称加密。
对称加密

就是指加密和解密时使用的密钥都是同一个,是“对称”的。只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。

TLS 里有非常多的对称加密算法可供选择,比如 RC4、DES、3DES、AES、ChaCha20 等,但前三种算法都被认为是不安全的,通常都禁止使用,目前常用的只有 AES 和 ChaCha20。

加密分组模式

对称算法还有一个“分组模式”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密(即密钥)转化为大秘密(即密文)。

最早有 ECB、CBC、CFB、OFB 等几种分组模式,但都陆续被发现有安全漏洞,所以现在基本都不怎么用了。最新的分组模式被称为 AEAD(Authenticated Encryption with Associated Data),在加密的同时增加了认证的功能,常用的是 GCM、CCM 和 Poly1305。

非对称加密

对称加密看上去好像完美地实现了机密性,但其中有一个很大的问题:如何把密钥安全地传递给对方,术语叫“密钥交换”

它有两个密钥,一个叫**“公钥”(public key**),一个叫“私钥”(private key)。两个密钥是不同的,“不对称”,公钥可以公开给任何人使用,而私钥必须严格保密。

公钥和私钥有个特别的“单向”性,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。

非对称加密算法的设计要比对称算法难得多,在 TLS 里只有很少的几种,比如 DH、DSA、RSA、ECC 等。

混合加密
虽然非对称加密没有“密钥交换”的问题,但因为它们都是基于复杂的数学难题,运算速度很慢,即使是 ECC 也要比 AES 差上好几个数量级。如果仅用非对称加密,虽然保证了安全,但通信速度有如乌龟、蜗牛,实用性就变成了零。

这就是现在 TLS 里使用的混合加密方式,其实说穿了也很简单:

在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题

然后用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。对方拿到密文后用私钥解密,取出会话密钥。

这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。
总结

1、加密算法的核心思想是“把一个小秘密(密钥)转化为一个大秘密(密文消息)”,守住了小秘密,也就守住了大秘密;

2、对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换,常用的有 AES 和 ChaCha20;

3、非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢,常用的有 RSA 和 ECC;

4、把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密,也就是 TLS 里使用的加密方式。

数字签名与证书

在机密性的基础上还必须加上完整性、身份认证等特性,才能实现真正的安全。

摘要算法

实现完整性的手段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)

你一定在日常工作中听过、或者用过 MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1),它们就是最常用的两个摘要算法,能够生成 16 字节和 20 字节长度的数字摘要。但这两个算法的安全强度比较低,不够安全,在 TLS 里已经被禁止使用了。目前 TLS 推荐使用的是 SHA-1 的后继者:SHA-2。

数字签名

这个东西就是非对称加密里的“私钥”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。

1、摘要算法用来实现完整性,能够为数据生成独一无二的“指纹”,常用的算法是 SHA-2;

2、数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;

3、公钥的分发需要使用数字证书,必须由 CA 的信任链来验证,否则就是不可信的;

4、作为信任链的源头 CA 有时也会不可信,解决办法有 CRL、OCSP,还有终止信任。

TLS1.2的连接过程

总结

1、HTTPS 协议会先与服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接;

2、握手的目标是安全地交换对称密钥,需要三个随机数,第三个随机数“Pre-Master”必须加密传输,绝对不能让黑客破解;

3、“Hello”消息交换随机数,“Key Exchange”消息交换“Pre-Master”;

4、“Change Cipher Spec”之前传输的都是明文,之后都是对称密钥加密的密文

HTTPS的优化

1、可以有多种硬件和软件手段减少网络耗时和计算耗时,让 HTTPS 变得和 HTTP 一样快,最可行的是软件优化;

2、应当尽量使用 ECDHE 椭圆曲线密码套件,节约带宽和计算量,还能实现“False Start”;

3、服务器端应当开启“OCSP Stapling”功能,避免客户端访问 CA 去验证证书;

4、会话复用的效果类似 Cache,前提是客户端必须之前成功建立连接,后面就可以用“Session ID”“Session Ticket”等凭据跳过密钥交换、证书验证等步骤,直接开始加密通信。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值