参考:《透视 HTTP 协议》— 罗剑锋
一、相关概念
【TCP/IP协议】:是目前网络世界“事实上”的标准通信协议,是一系列网络通信协议的统称;
【TCP 协议】: 传输控制协议,负责数据在两点之间可靠的、字节流的传输;
-- “可靠”是指保证数据不丢失,
-- “字节流”是指保证数据完整
【IP协议】:使用IP地址,实现寻址和路由;
【HTTP 协议】:超文本传输协议,简单来说就是,HTTP协议 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范;
【DNS域名解析】:将域名解析成计算机识别的IP地址;
【URI】:(Uniform Resource Identifier), 统一资源标识符,使用它就能够唯一地标记互联网上资源,包含URL 和 URN;
【URL】:(Uniform Resource Locator), 统一资源定位符,也就是我们俗称的“网址”;
URL是 URI 的一个子集,不过因为这两者差异不大,所以通常不会做严格的区分。
二、 TCP协议分层
TCP/IP 协议是一个“有层次的协议栈”,它的层次顺序是“从下往上”的,分为以下四个层次:
image.png第一层: 链接层(link layer),也叫MAC层
负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备;
第二层: 网际层(internet layer),也叫网络互连层
IP 协议就工作在这一层;
第三层: 传输层(transport layer)
TCP 协议工作在这一层,还有UDP协议;
第四层: 应用层(application layer)
HTTP 协议、DNS域名解析都工作在这一层;
MAC 层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包。
OSI 网络分层模型:国际标准组织(ISO)设计的新的网络分层模型,目的是想用这个新框架来统一既存的各种网络协议。包含七层:
OSI 为每一层标记了明确了编号,最底层是一层,最上层是七层。
第一层:物理层,网络的物理形式,例如电缆、光纤、网卡、集线器等等;
第二层:数据链路层,它基本相当于 TCP/IP 的链接层;
第三层:网络层,相当于 TCP/IP 里的网际层;
第四层:传输层,相当于 TCP/IP 里的传输层;
第五层:会话层,维护网络中的连接状态,即保持会话和同步;
第六层:表示层,把数据转换为合适、可理解的语法和语义;
第七层:应用层,面向具体的应用传输数据。
以上两种分层结构,也就是我们常说的“【四层模型】”、“【七层模型】”。
OSI 的分层模型在四层以上分的太细,而 TCP/IP 实际应用时的会话管理、编码转换、压缩等和具体应用经常联系的很紧密,很难分开。例如,HTTP 协议就同时包含了连接管理和数据格式定义。
【四层负载均衡】: 所谓的“四层负载均衡”,就是指根据OSI 的分层模型,工作在传输层上
,基于 TCP/IP 协议的特性,例如 IP 地址、端口号等实现对后端服务器的负载均衡。
【七层负载均衡】:所谓的“七层负载均衡”,就是根据OSI 的分层模型,工作在应用层上
,看到的是 HTTP 协议,解析 HTTP 报文里的 URI、主机名、资源类型等数据,再用适当的策略转发给后端服务器。
TCP 协议 vs UDP协议?
-
状态不同
-- TCP 是一个有状态的协议,需要先与对方建立连接然后才能发送数据,开始处于 CLOSED 状态,连接成功后是 ESTABLISHED 状态,断开连接后是 FIN-WAIT 状态,最后又是 CLOSED 状态;
-- 而 UDP 则是无状态的,不用事先建立连接就可以任意发送数据; -
数据的可靠性不同
-- TCP协议保证数据的可靠性和完整性,如果数据包丢失,会重新发送;
-- 而 UDP 不保证数据一定会发到对方,如果数据包丢失,不会重新发送; -
数据传输的形式不相同
-- TCP 的数据是连续的“字节流”,有先后顺序,
-- 而 UDP 则是分散的小数据包,是顺序发,乱序收,无法还原成完整数据;
有了IP为啥还要MAC?
- MAC 地址更像是身份证或者手机号,是一个唯一的标识,无定位功能;
- IP 地址,才是有远程定位功能
发送数据就好比送快递,根据IP地址只能找到具体位置,具体分送到谁的手中还需要手机号区分
三、HTTP 利用 TCP/IP 协议栈传输数据的方式
HTTP 利用 TCP/IP 协议栈传输数据时,
传输过程,是通过协议栈从上向下,每一层都添加本层的专有数据,层层打包,然后通过下层发送出去;
接收数据则是相反的操作,从下往上穿过协议栈,逐层拆包,每层去掉本层的专有头,上层就会拿到自己的数据。
HTTP数据传输过程.jpg二层转发 和 三层路由 是什么?
所谓的二层转发、三层路由,只是设备上运行在不同的网络分层而已;
【二层转发】: 也叫二层设备,设备工作在OSI 网络分层模型中第二层数据链路层(交换机),拿到目标MAC地址后,建立MAC地址和端口的映射关系,来决定往哪个端口转发;
简单来说,就是指接收到数据包后,只把数据包的 MAC 头去掉,看看到底是丢弃、转发,还是自己留着;
【三层路由】: 也叫三层设备,设备工作在OSI 网络分层模型第三层网络层,拿到IP地址后,决定路由到哪个网络;
简单来说,就是把数据包的 MAC 头去掉之后,再把 IP 头也去掉,看看到底是丢弃、转发,还是自己留着;
四、DNS解析
【DNS域名系统】:是一个三层树状、分布式的查询系统,包含:
-
根域名服务器(Root DNS Server):管理顶级域名服务器,返回顶级域名服务器的 IP 地址;
-
顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,返回自己域名下的权威域名服务器 IP 地址;
-- 比如 com 顶级域名服务器可以返回 baidu.com 域名服务器的 IP 地址;
-- 常用的顶级域名有com、net、edu、cn、org等 -
权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,
-- 比如 baidu.com 权威域名服务器可以返回 www.baidu.com 的 IP 地址。
【域名】: 主要用来代替 IP 地址,域名本质上还是个名字空间系统,
-- 每个域名都是独一无二的,可以作为一种身份的标识
-- 级别从左到右逐级升高
核心 DNS 系统之外,为了减轻域名解析的压力,能够更快地获取结果,引入了“缓存”,
- 许多大公司、网络运行商都会建立自己的 DNS 服务器
- 操作系统里也会对 DNS 解析结果做缓存
-- 浏览器缓存
-- 操作系统中的hosts文件(主机映射”文件)
DNS解析完整的解析过程:
-
浏览器本地缓存 ->操作系统缓存、 hosts文件 ->本地DNS服务器
-- 此过程是递归查询,一旦查到,寻址完成
-- 如果没有查到,则继续开始下面的查询步骤 -
根域名服务器 -> 顶级域名服务器 -> 权威域名服务器 - > 完整 Ip地址
-- 此过程为迭代查询
-- 以www.baidu.com为例,访问根域名服务器拿到com顶级域名服务器的Ip地址 ->访问“com”顶级域名服务器拿到baidu.com域名服务器的IP地址->最后访问“baidu.com”域名服务器拿到www.baidu.com地址。
六、HTTP 协议
1. 浏览器 HTTP 请求过程
面试时,我们常被问到“在地址栏里输入网址再按下回车发生了什么?”,其实就是在考察我们是否了解浏览器 HTTP 请求过程,其过程大致可以总结为以下几个:
-
如果网址中不知道IP地址,需要先去进行域名解析,拿到服务器的IP 地址;
-- 如果知道IP地址,则直接跳过这一步,如 http://127.0.0.1/ -
浏览器用 TCP 的三次握手与服务器建立连接;
-
浏览器向服务器发送拼好的报文;
-
服务器收到报文后处理请求,同样拼好报文再发给浏览器;
-
浏览器解析报文,渲染输出页面。
2. HTTP 的消息报文
HTTP 协议的核心部分是传输时的消息报文,由于 TCP/IP 协议负责底层的具体传输工作,HTTP 协议基本上不用在这方面操心太多。
HTTP 协议的请求报文和响应报文的结构基本相同,由以下几个部分组成:
-
起始行(start line):描述请求或响应的基本信息,也叫“请求行”或者“状态行”;
-
头部字段集合(header):使用 key-value 形式更详细地说明报文;
-
空白行:就是为了分隔header和body,因为http是纯文本的协议;
-
消息正文(entity):实际传输的数据,也被称为“body”
注意:在 header 和消息正文 之间必须有一个“空行”,为了分隔header和body。
起始行和头部字段又被合称为“请求头”或“响应头”,消息正文又称为“实体”;
HTTP的消息报文.png头字段 header
HTTP 报文的解析和处理实际上主要就是对头字段的处理,HTTP 协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类:
1. 通用字段:在请求头和响应头里都可以出现;
- Date:表示 HTTP 报文创建的时间
2. 请求字段:只能出现在请求头里,目的是为了说明请求信息或者额外的附加条件;
- Host :目标主机的域名/IP地址,告诉服务器这个请求应该由哪个主机来处理(请求头中必须要有此字段);
- User-Agent:说明当前客户端信息
- Accept: 告诉服务器客户端接收数据时可理解的数据类型
- Accept-Charset:客户户端接收数据时支持的字符集
- Accept-Encoding:客户端接收数据时支持的压缩格式
- Accept-Language: 客户端接收数据时可理解的自然语言
注意:q=value,表示内容协商的优先级,权重的最大值是 1,最小值是 0.01,默认值是 1,如果值是 0 就表示拒绝
Accept: text/html,application/xml;q=0.9,*/*;q=0.8
它表示浏览器最希望使用的是 HTML 文件,权重是 1,
其次是 XML 文件,权重是 0.9,
最后是任意数据类型,权重是 0.8。
服务器收到请求头后,就会计算权重,再根据自己的实际情况优先输出 HTML 或者 XML
3. 响应字段:只能出现在响应头里,补充说明响应报文的信息;
- Server:说明提供 Web 服务的软件名称和版本号
- Connection:keep-alive长链接
- Vary: 记录服务器在内容协商时参考了哪些请求头字段
-- Vary 字段可以认为是响应报文的一个特殊的“版本标记”,每当 Accept 等请求头变化时,Vary 也会随着响应报文一起变化;
-- 也就是说,同一个 URI 可能会有多个不同的“版本”,主要用在传输链路中间的代理服务器实现缓存服务。
Vary: Accept-Encoding,User-Agent,Accept
4. 实体字段:它实际上属于通用字段,主要用来专门描述 消息正文 的额外信息。
- Content-Length:消息正文的长度
- Content-Type: 实体数据的真实类型及编码字符集格式
- Content-Encoding:实体数据使用的压缩格式
- Content-Language: 实体数据真实使用的语言类型
- Transfer-Encoding: chunked 表示报文消息正文(body部分)不是一次性发过来的,而是分成了许多的块(chunk)逐个发送。
3. HTTP 请求的常用方法
HTTP请求方法的实际含义就是客户端发出了一个“动作指令”,即客户端“请求”或者“指示”服务器根据某个动作指令来操作远程服务器上的资源。
-
GET:从服务器获取资源;
-
HEAD:从服务器获取资源,但是服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”;
-- 如想要检查一个文件是否存在,只要发个 HEAD 请求就可以了,没有必要用 GET 把整个文件都取下来 -
POST:向服务器提交数据;通常是指新建一个数据
-
PUT:也是用来向服务器提交数据,但更注重的是更新数据;
-
DELETE:删除数据;
【安全】:指请求方法不会修改服务器中的数据。如GET、 HEAD;而POST、PUT、DELETE则会修改数据,是不安全的。
【幂等】:是指多次执行相同的操作,结果都是相同的。
- GET 和 HEAD 是幂等的;
- DELETE 也是幂等的,即多次删除同一个资源,结果都是“资源不存在了“;
- PUT 是幂等的,即多次相同方式更新一个资源,结果都是一样的;
- POST 不是幂等的;每次创建或提交都会生成一个新的资源;
GET 与POST的区别是什么?
-
用途不同:
--GET用于从服务器端获取数据,即包括静态资源HTML|JS|CSS|Image,也包括动态数据,主要用展示
-- POST用于向服务器提交数据,如增删改数据,提交一个表单新建一个用户、或修改一个用户等 -
参数不同:
-- GET传递的参数会在URL展示,长度限制一般为4K左右,
-- POST传递的参数在请求body(消息正文中),没有大小限制 -
发送请求方式不同:
-- GET请求时,浏览器会把请求头和data一起发送出去,服务器响应200,直接返回数据
-- POST请求时,浏览器先发送请求头,服务器响应100 continue,浏览器再发送data,服务器响应200,返回数据 -
幂等与安全程度不同:
-- GET是幂等的,不会修改服务器中的数据
-- POST是不幂等的,会修改服务器中的数据
4. HTTP 响应状态码
-
1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
-
2××:请求成功;
-- 200 OK,报文已经收到并被正确处理;
-- 204 No Content,请求成功,但响应头后没有 body 数据; -
3××:重定向,资源位置发生变动,同时返回一个Location字段,需要客户端重新发送请求;
-- 301永久重定向
-- 302 临时重定向
-- 304 资源未修改;用于缓存控制 -
4××:客户端错误,请求报文有误,服务器无法处理;
-- 400 Bad Request,只是一个笼统的错误,表示请求报文有错误
-- 403 资源禁止访问
-- 404 资源未找到
-- 408 Request Timeout:请求超时,服务器等待了过长的时间; -
5××:服务器错误,服务器在处理请求时内部发生了错误。
-- 500,也是一个通用的错误码
-- 502 ,通常是服务器作为网关或者代理时返回的错误码,表示服务器自身正常,访问后端服务器时发生错误
-- 503 服务器正忙,暂时无法响应
重定向主要用在未登录或者权限不足的场景,跳转到对应的登录或提升页面之中。
外部重定向 VS 内部重定向:
【外部重定向】: 也叫站外重定向,需要再次建立一次TCP连接,再次的发起请求,地址栏的地址会发生变化
【内部重定向】:也叫站内重定向,可以长连接复用,不需要需要再次建立一次TCP连接,地址栏的地址不变。
5. HTTP 协议的特点:
- 简单、灵活、易于扩展;
- HTTP 协议是一个“可靠”的传输协议;
- HTTP 是有连接无状态;
-- 相对于UDP协议来说,HTTP是有连接,协议顺序发包顺序收包,按照收发的顺序管理报文;
-- 相对于TCP协议来说,“无状态"是指客户端每次http请求都是独立的,多个请求之间没有直接关系,服务器不会主动保留每次http请求的状态; - HTTP 协议使用的是请求 - 应答通信模式;
- HTTP 协议使用明文传输;
-- “明文”意思就是协议里的报文(准确地说是 header 部分)不使用二进制数据,而是用简单可阅读的文本形式。
HTTP 协议使用的是请求 - 应答通信模式,规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。
【队头阻塞】:(Head-of-line blocking),当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。
为了解决这个问题,就诞生出许多解决办法,如HTTP 官方标准里就有“缓存”,非官方的“花招”就更多了,例如切图、数据内嵌与合并,域名分片、JavaScript“黑科技”等等。
HTTP 里解决队头阻塞常用的办法有以下两种:
-
客户端使用并发连接
:是指一个客户端可以同时对一个域名发起多个连接,用数量来解决质量的问题。
浏览器对单个域名的并发连接数量有限制,一般为6~8个,所以为了进一步提高连接数就有了“域名分片”技术,即将原来一个域名分成多个域名,但最后指向的服务器还是原来那一台。
-
域名分片
,使用多个域名指向同一台服务器
-- 域名分片解决的是客户端并发的问题,可以创建更多的连接。
-- 如浏览器限制一个域名最多6个连接,域名分3片,那么浏览器就可以同时建立18个连接,显然就能够并发更多请求,获取数据也就快了
【高并发请求】:是服务器端的概念,是指一个服务器同时有多个客户端发起连接请求
【负载均衡】:是服务器端的概念,是指把服务器大量的客户端连接请求均匀分散到集群里的多台服务器。
6. HTTP 传输大文件的方法
随着互联网的发展, HTTP 可以传输的数据类型越来越多,不仅是文本,也能传输图片、音频和视频,随之文件的大小也开始变得越来越大。面对这种发展,如何在有限的带宽下高效快捷地传输这些大文件是急需一个重要的问题。
HTTP 协议的解决办法:
数据压缩
如gzip、deflate、br,压缩 HTML 等文本文件是传输大文件最基本的方法;
分块传输
响应头里使用字段Transfer-Encoding: chunked,来表示报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送;
注意:Transfer-Encoding: chunked
和 Content-Length
这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked)。
范围请求
HTTP 协议使用了“范围请求”(range requests)的概念,允许客户端在请求头里使用专用字段来表示只获取文件的一部分,相当于是客户端的“化整为零”。
响应状态码必须是 206
服务器可以在响应头里使用字段Accept-Ranges: bytes
,告知客户端是否支持范围请求。
多段数据
响应报文的数据类型是multipart/byteranges
,即一次请求多个范围。
以上几种方法可以混合起来使用。
7. HTTP的连接管理:
【短连接】:每次发送请求都要重新建立连接,请求完成就断开
缺点:TCP协议中,建立连接和断开连接非常耗时,如此传输效率很低
【长连接】: 也叫持久连接、连接复用,一次连接,多次可用;
-- 默认启用长连接,
-- 字段Connection: keep-alive,
-- 如果TCP 长时间连接却不发送请求,容易造成服务器资源浪费,因此需要客服端主动提示关闭
// 请求头
Connection: keep-alive 告诉服务器需要长连接
Connection: close 告诉服务器此次通信后就关闭连接
// 响应头
Connection: keep-alive 服务器支持长连接
Connection: close 此次通信后就关闭连接了
服务器端通常不会主动关闭连接,但也可以使用一些策略。
8. Cookie
HTTP协议是无状态的,为了识别客户端用户,使用Cookie便可以实现用户身份识。
当用户通过浏览器第一次访问服务器的时候,服务器通过 Set-Cookie 字段为当前浏览器设置标识,随着响应报文一同发给浏览器;
客户端浏览器收到响应报文,看到里面有 Set-Cookie,将值放进 Cookie 字段,下次请求时一起发给服务器。
注意:Cookie 本质上就是服务器委托浏览器存储在客户端里的一些数据,Cookie 是由浏览器负责存储的,而不是操作系统。所以,它是“浏览器绑定”的,只能在本浏览器内生效。
Cookie 的生存周期
Cookie 的生存周期即Cookie的有效期,一旦超过这个有效期,浏览器就认为是 Cookie 失效,在存储里删除,也不会发送给服务器。
Cookie 的有效期可以使用 Expires 和 Max-Age 两个属性来设置。
- Max-Age: 用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。优先级较高
-- 时间起点是收到响应报文的时刻,如Max-Aage=10,即收到响应报文10s之后失效,优先级高
- Expires: 用的绝对时间点,即具体的失效时期, 如 Expires=GMT 2019 年 6 月 7 号 8 点 19 分
注意:Expires 和 Max-Age 可以同时出现,两者的失效时间可以一致,也可以不一致,但浏览器会优先采用 Max-Age 计算失效期。
Cookie 的安全性
Cookie 的安全性主要存在以下两个方面:
- 跨站脚本攻击获取cookie :在 JS 脚本里可以用 document.cookie 来读写 Cookie 数据,容易导致
跨站脚本攻击(Cross Site Scripting,为了区别CSS称为XSS)
窃取数据; - 跨站请求伪造:恶意网站获取Cookie,利用目标网站对用户网页浏览器的信任,引发
跨站请求伪造(XSRF)
跨站请求伪造.png
解决方法:
- 使用httpOnly属性,通知浏览器此 Cookie 只能通过浏览器 HTTP 协议传输,浏览器的 JS 引擎就会禁用 document.cookie;
- 使用SameSite属性,可以防范“跨站请求伪造”(XSRF)攻击;
-- 设置“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,
-- 而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。
七、 HTTP缓存策略
参考文章:https://mp.weixin.qq.com/s/cUqkG3NETmJbglDXfSf0tg
1. 浏览器三级缓存机制(即访问缓存的优先级):
-
内存(memory cache)
-- 先查找内存(memory cache),如果有则直接读取 -
磁盘缓存(disk cache),
-- 因为严格遵守HTTP 协议头中的字段,所以也叫 HTTP cache,平时所说的强制缓存,对比缓存,以及 Cache-Control 等,也都归于此类;
-- 内存没有,再查找磁盘缓存,如果有则直接读取 -
磁盘没有,则发起网络请求,收到响应的资源缓存到内存和磁盘上 。
2. HTTP缓存的强制缓存
强制缓存的含义是,当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。
强制缓存直接减少请求数,常用的字段有 Cache-control 和 Expires
Cache-Control
包含以下几个取值:
-
max-age, 最常使用,表示资源的有效期,使用相对时间
-- 时间的计算起点是响应报文的创建时刻(即 Date 字段,也就是离开服务器的时刻),说包含了在链路传输过程中所有节点所停留的时间。 -
no-store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;
-
no-cache:允许缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本;
-
must-revalidate:缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证
缺点:强缓存情况下,只要缓存还没过期,就会直接从缓存中取数据,服务器数据变化,拿不到最新数据。
解决方法:在修改后的资源加上随机数,确保不会从缓存中取。(修改文件名)
Expires
表示缓存到期时间,是一个绝对的时间点
Expires: Thu, 10 Nov 2017 08:45:11 GMT
3. 协商缓存,也叫条件请求
当强制缓存失效(超过规定时间)时,就需要使用协商缓存,由服务器决定缓存内容是否有效。
条件请求一共有 5 个头字段,我们最常用的是if-Modified-Since
和If-None-Match
这两个。
需要第一次的响应报文预先提供Last-modified
和ETag
,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。
如果资源没有变,服务器就回应一个“304 Not Modified”,表示缓存依然有效,浏览器就可以更新一下有效期,然后放心大胆地使用缓存了。
【Last-modified】:最近一次修改时间
【ETag】:是资源的一个唯一标识,资源本身是否发生变化,Etag 的优先级高于 Last-Modified
浏览器要请求资源时的完完整查找过程:
-
先查找 内存,有则直接返回,没有继续查找磁盘缓存disk cache
-
如果有强制缓存,判断强制缓存是否失效,没有则去判断是否有协商缓存
-- 如果强制缓存未失效,则使用强制缓存,不再请求服务器,这时的状态码全是 200
-- 如果强制缓存已失效,则使判断是否有协商缓存 -
如果有协商缓存,则发起请求,服务器判断当前资源是否有效,
-- 如果资源有效, 服务器如果返回304,继续使用缓存,
-- 如果资源无效,则返回新资源,状态码200 -
如果也无协商缓存,则发送网络请求,等待服务器响应新资源
F5刷新或者点击刷新按钮和Ctrl+F5 强制刷新的区别?
-
F5刷新或者点击刷新时,设置“Cache-Control: max-age=0”,跳过强缓存判断,直接进行协商缓存判断;
-- 即浏览器会在请求头里加一个“Cache-Control: max-age=0”。因为 max-age 是“生存时间”,而本地缓存里的数据至少保存了几秒钟,所以浏览器就不会使用缓存,而是向服务器发请求。服务器看到 max-age=0,也就会用一个最新生成的报文回应浏览器。 -
按下Ctrl+F5强制刷新时,请求头中 会添加Cache-Control: no-cache,并清空If-Modified-Since 和 If-None-Match,跳过强缓存和协商缓存,直接从服务器拉取资源。
八、HTTP代理
HTTP代理,就是指在客户端和服务器原本的通信链路中插入的一个中间环节,也是一台服务器,但提供的是“代理服务”。
所谓的“代理服务”,服务本身不生产内容,而是处于中间位置转发上游的请求和下游的响应,具有双重身份;既可以为客户端提供代理服务,也可以为服务器提供代理服务 。
1.代理的种类
代理有有以下几种:
- 匿名代理:隐藏被代理的主机,只能看到提供代理的主机
- 透明代理:被代理的主机、代理主机都可以看到
- 正向代理:为户端提供代理,向客服务器发送请求
- 反向代理: 为服务器提供代理,向客户端响应请求(如CDN)
2.代理可以实现的功能:
-
负载均衡,目的是实现最近最少使用,把对一台服务器的多个请求分散到集群中的多台服务器上;
-
内容缓存,暂存、复用服务器响应;
-
健康检查,使用“心跳”等机制监控后端服务器,目的是把故障服务器清理出去,保证服务高可用;
-
安全防护,目的是保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载
-
加密卸载,对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本;
-
数据过滤:拦截上下行的数据,任意指定策略修改请求或者响应;
缺点:
1. 增加了链路长度,响应时间成本高
2. 代理处在 HTTP 通信过程的中间位置,容易引发一些信任问题
3. 缓存代理
缓存代理:代理服务器每次接收到新的请求时都向源服务器发送一次请求资源的操作,增加了链路长度,响应时间成本高,因此使用代理实现缓存可以减轻应用服务器的并发压力,提高性能。
因为代理向源服务器时是客户端,在面向客户端时又是服务器,所以它即可以用客户端的缓存控制策略也可以用服务器端的缓存控制策略。
4. 代理相关头字段
【Via】:标明代理主机的身份
用法:
Via: 代理主机1的IP(或者域名),代理主机2的IP(或者域名)......
Via 是一个通用字段,请求头或响应头里都可以出现。每当报文经过一个代理节点,代理服务器就会把自身的信息追加到字段的末尾,就像是经手人盖了一个章。
HTTP代理.png【X-Forwarded-For】: 为谁而转发,依次追加的是被代理的 IP 地址
所以,最左边的 IP 地址就是客户端的地址。
【X-Real-IP】:表明真实 的IP,即被代理主机的真实IP
5. CDN(内容分发网络)
CDN就是专门为解决“长距离”上网络访问速度慢而诞生的一种网络应用服务,CDN 的最核心原则是“就近访问”。
CDN 投入了大笔资金,在全国、乃至全球的各个大枢纽城市都建立了机房,部署了大量拥有高存储高带宽的节点,构建了一个专用网络。有了这个高速的专用网之后,CDN 就要“分发”源站的“内容”了,用到的就是“缓存代理”技术,把源站的内容逐级缓存到网络的每一个节点上。
用户在上网的时候就不直接访问源站,而是访问离他“最近的”一个 CDN 节点,术语叫“边缘节点”(edge node),其实就是缓存了源站内容的代理服务器,实现了“网络加速”。
CDN.png九、HTTPS
HTTPS 在HTTP 的基础增加了机密性、完整性、身份认证、不可否认四大安全特性。
HTTPS协议名“https”,默认端口号 443,下层的传输协议是SSL/TLS,HTTPS其实就是让 HTTP 运行在了安全的 SSL/TLS 协议上,除此之外,HTTPS的语法、语义仍然是 HTTP。
SSL 即安全套接层(Secure Sockets Layer)
,在 OSI 模型中处于第 5 层(会话层),在 1999 年把它改名为 TLS(传输层安全,Transport Layer Security)
,正式标准化,版本号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1。
【密码套件】:也叫加密套件,浏览器和服务器在使用 TLS 建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为“密码套件”。
HTTPS.png1. HTTPS的特性:
1.1 机密性
实现机密性主要是通过对数据加密法来实现,即加密算法。
所谓加密”(encrypt),就是把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊“钥匙”的人才能再转换出原始文本;
这里的“钥匙”就叫做密钥”(key)
; 加密前的消息叫“明文”
(plain text/clear text),加密后的乱码叫“密文”
(cipher text),使用密钥还原明文的过程叫“解密”
加密解密的操作过程就是“加密算法
。
加密又可以分为对称加密、非对称加密、混合加密。
对称加密
对称加密是指加密和解密时使用的密钥都是同一个,是“对称”的,一次会话一个密钥。
对称加密存在一个很大的问题:如何把密钥安全地传递给对方,术语叫“密钥交换”。
非对称加密,也叫公钥加密算法
非对称加密有两个密钥,一个叫“公钥”(public key),一个叫“私钥”(private key)。两个密钥是不同的,“不对称”,公钥可以公开给任何人使用,而私钥必须严格保密。
公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密,非对称加密可以解决“密钥交换”的问题。
缺点:由于非对称加密基于复杂的数学难题,运算速度很慢,所以导致通信速度慢,实用性差。
混合加密
同时使用对称加密和非对称加密,兼顾了安全和性能。
在通信刚开始的时候使用非对称算法,首先解决密钥交换的问题;
后续就不再使用非对称加密,全都使用对称加密。
1. 2 完整性
实现完整性的手段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。
摘要算法
你可以把摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”。
摘要算法保证了“数字摘要”和原文是完全等价的,所以,我们只要在原文后附上它的摘要,网站收到后,计算一下消息的摘要,然后将原文和摘要做个对比,如果一致,就说明消息是完整可信的,没有被修改,就能够保证数据的完整性。
1.3 身份认证
数字签名
数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。
签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解,只要你和网站互相交换公钥,就可以用“签名”和“验签”来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能够保证通信双方的身份。
问题:公钥无法保证一定是安全正确的
数字证书和 CA(证书认证机构)
为了保证公钥证公钥无法伪造,是可信的,就需要 CA(Certificate Authority,证书认证机构)的约束。
CA(证书认证机构)它就像网络世界里的公安局、教育部、公证中心,具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。
CA 对公钥的签名认证也是有格式的,除了自身公钥外,还包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成数字证书(Certificate)
。
1.4 不可否认
“数字签名”,同时实现“身份认证”和“不可否认”。
2. TLS协议
在 HTTP 协议里,使用TCP协议“三次握手”建立连接后,浏览器会立即发送请求报文;
但是 HTTPS 协议里,在 TCP 建立连接之后,还需要再进行一次握手即TLS 握手,建立安全连接,然后才收发 HTTP 报文。
一个 TLS 握手的步骤,这个步骤最长可以花费两个消息往返,也就是 2-RTT。
TLS握手流程:
第一次:客户端 ->服务器
-- 客户端发送一个加密套件列表(加密方法列表)
-- 和一个随机数(Client Random)
第二次:服务器 -> 客户端
-- 服务器发送一个选定的加密套件
-- 一个随机数( Server Random)
-- 一个数字证书
第三次:客户端 ->服务器
-- 客户端验证证书
-- 客户端保存数字证书中的公钥,并生成随机数 Pre-Master
-- 然后利用公钥对 Pre-Master 加密,并向服务器发送加密后的数据
第四次:服务器 -> 客户端
-- 服务器收到密文,使用私钥进行解密
-- 返回确认消息
3. HTTP连接太慢,如何优化?
通常所说的“HTTPS 连接慢”指的就是刚开始建立连接的那段时间。
硬件方面优化:
- 选择更快的 CPU;
- 选择“SSL 加速卡”,加解密时调用它的 API,让专门的硬件来做非对称加解密,分担 CPU 的计算压力;
- SSL 加速服务器”,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算,性能自然要比单纯的“加速卡”要强大的多。
软件方面优化:
- 软件升级
-- 由于这些软件在更新版本的时候都会做性能优化、修复错误,只要运维能够主动配合,这种软件优化是最容易做的,也是最容易达成优化效果的。 - 协议优化
- 会话复用
-- 会话复用分两种,第一种叫“Session ID”,就是客户端和服务器首次连接后各自保存一个会话的 ID 号,内存里存储主密钥和其他相关的信息。当客户端再次连接时发一个 ID 过来,服务器就在内存里找,找到就直接用主密钥恢复会话状态,跳过证书验证和密钥交换,只用一个消息往返就可以建立安全通信。
-- 第二种“Session Ticket”
十、HTTP/2
由于 HTTPS 已经在安全方面做的非常好了,所以 HTTP/2 的唯一目标就是改进性能,HTTP/2可以被认为是“更安全的 HTTP、更快的 HTTPS”。
1. 兼容 HTTP/1
HTTP/2 把 HTTP 分解成了“语义”和“语法”两个部分,“语义”层不做改动,比如请求方法、URI、状态码、头字段等概念都保留不变。
HTTP/2 没有引入新的协议名,仍然用“http”表示明文协议,用“https”表示加密协议。
2. 头部压缩
HTTP/1 里可以用头字段“Content-Encoding”指定 Body 的编码方式,但对Header 却被无视了,没有针对它的优化手段;
HTTP/2 开发了专门的“HPack”算法实现对头部数据的压缩,可以达到 50%~90% 的高压缩率。
3. 二进制格式
HTTP/2 摒弃了HTTP/1 里纯文本形式的报文,不再使用肉眼可见的 ASCII 码,而是全面采用二进制格式,把原来的“Header+Body”的消息“打散”为数个小片的二进制“帧”(Frame),用“HEADERS”帧存放头数据、“DATA”帧存放实体数据。
4. 使用虚拟的“流”概念
“流”(Stream)的概念,它是二进制帧的双向传输序列,同一个消息往返的帧会分配一个唯一的流 ID。
在“流”的层面上看,消息是一些有序的“帧”序列,而在“连接”的层面上看,消息却是乱序收发的“帧”。多个请求 / 响应之间没有了顺序关系,不需要排队等待,也就不会再出现“队头阻塞”问题,降低了延迟,大幅度提高了连接的利用率。
【多路复用】( Multiplexing):是指多个往返通信都复用一个连接来处理。
-- 将报文分散为多个二进制“帧”,在一个TCP连接上,使用虚拟的“流”同时传输多个“碎片化”消息,解决了“队头阻塞”问题
-- “流”是并行发送的,每个"流"的二进制帧都带一个流ID,一个相当于流一个请求-应答
-- 服务器端接收到这些请求后,根据优先级决定优先返回哪些内容
【服务器推送】
-- 服务器可以主动向客户端发送数据,如浏览器请求 HTML 的时候提前把可能会用到的 JS、CSS 文件发给客户端,减少等待的延迟
十一、HTTP性能优化思考
服务器性能衡量的三个重要指标:
【RPS】:(Requests Per Second),吞吐量,即每秒处理请求数量,RPS 越高就说明服务器的性能越好
【并发数】,即服务器能够同时处理请求数量,并发数越大说明服务器的负载能力越高。
【响应时间】(time per request),每个请求的响应时间,反映了服务器的处理能力,响应时间越短,单位时间内服务器就能够处理更多请求,提高吞吐量和并发数。
服务器的性能优化方向:合理利用系统资源,提高服务器的吞吐量和并发数,降低响应时间;
客户端 HTTP 性能优化的关键就是:降低延迟,就是降低客户端与服务器一次请求响应的往反时间。
- 投资购买现成的硬件,如更强的 CPU、更快的网卡、更大的带宽、更多的服务器等
- HTTP缓存,减少请求次数
- 使用CDN缓存,降低延迟
- 合理使用长连接,连接复用
- 启用压缩、按需传输减少传输体积,提高响应时间
- 使用反向代理,负载均衡,提高服务器的吞吐量和并发数
- 资源合并,对就是把许多小资源合并成一个大资源,用一个请求全下载到客户端
TCP连接为什么需要“三次握手”?
参考文档:https://blog.csdn.net/jonathanxqs/article/details/45129027
- 为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误;
- 比如客户端的第一个请求由于网络延迟,阻塞等原因延迟发送到服务器,其实本次请求已经失效了,如果不通过握手确认就直接连接的话,服务器收到失效的请求报文后,就认为客户端重新发送了一次请求,建立了无效连接,浪费资源。
- 三次握手的目的是建立可靠的通信信道,确保客户端和服务器的发送和接收能力都没有问题。
-第一次握手:客户端发送建立连接的请求报文(SYN),服务器收到请求,服务端确定客户端发送能力ok;
-
第二次握手:服务器向客户端发送确认报文(ACK),客户端接收到服务器的SYN+ACK报文,确定服务端的接收和发送能力ok;
-
第三次握手:客户端再次向服务器确认报文(ACK),服务端接收到报文后,确定客户端接收能力ok,连接建立成功。
TCP断开连接为啥需要“四次挥手”?
参考文档: https://www.jianshu.com/p/0a81dfb307d7
TCP是一个全双工的连接,任何一方都可以发送数据接收数据,因此 TCP 有支持半关闭的特性,即连接的一端在关闭了发送数据能力后,但是仍然可以继续接收数据。
服务端在收到客户端断开连接Fin报文后,会先发送一个ACK包先告诉客户端收到关闭连接的请求,
但是服务器并不会立即关闭连接,只有当服务器的所有报文发送完毕之后,才发送FIN报文断开连接,因此需要四次挥手。
-
第一次挥手:客户端发送一个连接中断请求报文(FIN 报文), 等待服务器的确认;
-
第二次挥手:服务器收到连接中断请求后,发出一个确认报文(ACK),客户端收到确认报文后,进入等待状态,不知道服务器是否需仍有数据要发,因此需要等服务端发出的连接中断的请求报文;
-
第三次挥手:如果服务端也想断开连接了,也会发一个中断连接的请求报文(FIN 报文)给客户端
-
第四次挥手:客户端收到 FIN报文 之后,也会发送一个确认报文。
-- 注意:此时客户端没有立即关闭连接,而是等待一段时间 后,才会进入 CLOSED状态,目的是确保服务端收到自己的 ACK 报文。
-- 如果服务端在规定时间内没有收到客户端发来的 ACK 报文的话,服务端会重新发送 FIN 报文给客户端,客户端再次收到 FIN 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文给服务端,服务端收到 ACK 报文之后,就关闭连接了,处于 CLOSED 状态。
网友评论