*个人学习笔记,如有侵权,请立刻联系删除
计划做得多不如极客上路
老师背景:
罗剑锋(Chrono) 前奇虎360技术专家,Nginx/OpenResty开源项目贡献者
“To Be a HTTP Hero!”
HTTP关键技术(蒂姆-伯纳斯-李):
HTTP发展历程:
HTTP (HYPERText Transfer Protocol超文本传输协议) = 超文本 + 传输 + 协议
超文本:文本属于线性,超文本包括图片视频音频超链接等等,是非线性的网状结构关系
传输:搬运工,从A - > B 或者从A - > B - > C,HTTP是双向的
协议:一个或者多个的双方约定
HTTP是什么:
“HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范”。
HTTP不是什么:
HTTP不是互联网、不是编程语言、不是应用、HTTP更加不是一个孤立的协议。
在互联网世界里,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外,还有一些协议依赖于 HTTP,例如 WebSocket、HTTPDNS 等。这些协议相互交织,构成了一个协议网,而 HTTP 则处于中心地位。
小结:
HTTP 是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。HTTP 传输的是文字、图片、音频、视频等超文本数据。HTTP 是构建互联网的重要基础技术,它没有实体,依赖许多其他的技术来实现,但同时许多技术也都依赖于它。
1:上集
浏览器(B): chrome
服务器(Web Server):Apache、...
CDN(Content Diliver xxx):内容分发网络
2:下集
http://nginx.org/en/download.html
协议名:即访问该资源应当使用的协议,在这里是“http”;
主机名:即互联网上主机的标记,可以是域名或 IP 地址,在这里是“nginx.org”;
路径:即资源在主机上的位置,使用“/”分隔多级目录,在这里是“/en/download.html”。
TCP/IP网络分层
OSI网络分层模型
两个模型的映射关系
第一层:物理层,TCP/IP 里无对应;
第二层:数据链路层,对应 TCP/IP 的链接层;
第三层:网络层,对应 TCP/IP 的网际层;
第四层:传输层,对应 TCP/IP 的传输层;
第五、六、七层:统一对应到 TCP/IP 的应用层。
小结:
课下思考
域名的形式
“time.geekbang.org”
time:主机名,www(万维网服务)、mail(邮件服务)
geekbang:二级域名
org:顶级域名
域名的和解析
例如要访问“www.apple.com”:
注意:
当全世界的网民都在上网的时候,如果不采取别的手段,也会瘫痪:
域名的“新玩法”
课后思考
Q1:在浏览器地址栏里随便输入一个不存在的域名,比如就叫“www. 不存在.com”,试着解释一下它的 DNS 解析过程。
A: 前面提过,域名解析的过程是“自顶向下”,并且本地计算机、附近的DNS也会做缓存。所以解析过程是(发起访问"www.不存在.com" --> 操作系统找缓存 --> hosts文件映射 --> 内部DNS缓存(如果有) --> 网络运营商DNS缓存(非核心?) --> 根域名服务器 --> 顶级域名服务器(有继续,没有就返回) --> 权威域名服务器(同理) )
Q2:如果因为某些原因,DNS 失效或者出错了,会出现什么后果?
A:由A1得知,这个问题需要分析,本地是否由缓存,如果有,则无需转发至DNS,如果没有,返回错误
评论区补充发现:
“最小化”环境用到的应用软件:
Wireshark
Chrome/Firefox
Telnet
OpenResty
以下是部署的问题:
1、http_study已解压,openresty也在http_study目录下,http_study也在openresty下,但在http_study\www\start运行后提示windows找不到文件..\openresty\nginx
A: 问题本质,就是在运行自己写的Windows批脚本不要用管理员身份运行,运行路径会变为C:\System32,此时../openXXX就找不到了,如果非要,notepad改start改绝对路径。
2、Nginx 错误10013: An attempt was made to access a socket in a way forbidden by its access permissions
A: 1:netstat -aon | findstr :80 or 443(https)//找到端口占用情况 tasklist|findstr "进程号" //占用端口服务 ,任务管理器关掉服务
访问IP www.127.0.0.1/
访问域名 http://www.chrono.com
先讲两个访问方法的相同点:
1、浏览器通过URI、端口号,和Web服务器建立TCP连接,当然要三次握手,HTTP就可以干活了
2、然后Browser发送一条HTTP/1.1协议
3、然后回WebServer会返回一个HTTP/1.1 200 OK
4、浏览器ACK WebServer走的是UDP协议(这里没抓)
5、Browser解析HTML文件
区别:
1、通过域名访问的,需要访问一遍自己的缓存 + hots文件,最后才去DNS取
| 组成HTTP报文的结构分为三大类:
来看看实际报文结构:
抽象后的报文:
| 报文又分为以下两种:
HTTP报文又分为两种,一中是请求报文,一种是响应报文。他们有相同的地方,也有不同的地方。
相同点:
1、都有起始行、头部字段,都是CRLF表示结束。
抽象图如下:
以上值得注意的是:
不同之处:
1、请求报文的起始行叫请求行,响应报文的起始行叫状态行,两者抽象结构如下:
实际报文结构:
2、虽然说都有头部字段,但是有些字段是只能在请求报文,有些字段只能在响应报文里面,如下:
基本头字段表格
Host 只会出现在请求字段,用于区分多个域名指向同一个IP的情况 User-Agent 只能出现在请求头里面,用于限时当前浏览器的信息 Date 只会出现在响应头中,表示HTTP报文创建时间 Server 只能出现在响应头,表示当前服务的Web服务信息 Content-Length 表示body的长度
| 课后思考:
Q1、如果拼 HTTP 报文的时候,在头字段后多加了一个 CRLF,导致出现了一个空行,会发生什么?
A1: 刚开始以为是会忽略,但是评论区中说是只会吧CRLF当做body,老师也认同了。
Q2、讲头字段时说“:”后的空格可以有多个,那为什么绝大多数情况下都只使用一个空格呢?
A2:省流量,多一个占位符,多一个字节
| 关于HTTP请求的介绍
| HTTP关于安全与幂等
安全:指请求的方法是否会破坏服务器的资源,例如GET、HEAD是安全的,DELETE、POST、PUT是不安全的。
幂等:意思值多次执行相同的操作,结果都是相同的。
| 课后思考
Q1:你能把 GET/POST 等请求方法对应到数据库的“增删改查”操作吗?请求头应该如何设计呢?
A1:GET = SELECT,POST = INSERT OR UPDATE,这些行为都是谓语,其他是宾语 + 状语,数据库查询是查找什么东西,在哪里,有什么条件,比如HTTP GET方法就是访问谁,获取什么东西、有什么条件,一一对上即可。
Q2:你觉得 TRACE/OPTIONS/CONNECT 方法能够用 GET 或 POST 间接实现吗?
A2:
TRACE:用GET、POST实现,约定好URL或者data_field标记就好
OPTIONS:用GET、POST实现,约定好URL比约定key省事
CONNECT:用GET、POST实现,约定好URI,每次收到这个key或者URI的请求就转发(猜想)
评论区得知:
1、前端跨域请求常常用到OPTION 所有人都应该知道的跨域及CORS - 知乎
|> URI的基本格式
scheme:使用什么协议请求,如http、https、ftp、file、ldap、news
:// : 特定字符,必填但是就是做分隔,没别的用途
authority(hosts + port + path):host = 主机名(可以是ip地址)、port = 端口(不填默认端口80,https默认端口443)、path = 标记资源所在位置,用"/"开始,"/"分隔,
query: 参数
do some example:
http://nginx.org
http://www.chrono.com:8080/111
https://tools.ietf.org/html/rfc7230
file:///D:/http_study/www/
1、使用http协议访问,主机名是ngsinx.org,使用http默认端口80
2、使用http协议访问,主机名是www.chrono.com,端口号用8080,path是"/111"
3、使用https协议访问,主机名是tools.ietf.org,端口号443,path是“/html/rfc7230”
4、使用file协议访问,没有host,默认localhost,path是“/D:/http_study/www/”
|> 在浏览器中观察一次URI
GET方法后紧跟着path,因为Host字段就有有主机名了,就没必要再拼一次,由此得知客户端与服务端看的的URI是不一样的,客服端因为要查找,所以需要URI的完整信息,服务端看到的是报文,被删除协议名和主机名的URI
|> URI的查询参数
URI的查询参数,用“?”开始,但是不包括问号,用“key = value”的格式,用“&”来连接,一下是使用“http://www.chrono.com:8080/11-1?uid=1234&name=mario&referer=xxx”访问,看看Chrome中解析的URL:
|> URI的完整格式
与基本格式相比,多了以下两个部分:
1、`user:passwd@`,表示登录主机时的用户名和密码,由于把账密暴露出来,现在不用这种格式
2、`#fragment`,片段标识符,浏览器可以在获取资源后跳转到她指示的位置,服务器看不到。
|> URI的编码
在URI使用英语以外的语言,URI引用了编码机制,可以将ASCII码以外的字符和特殊字符做一个特殊的操作,既把它们转换与URI语义不冲突的形式,俗称“转义”,转义规则是直接转换为十六进制,在前面加个“%”。
看看浏览器是怎么做的:
copy浏览器的地址或者F12看看他的原型:
|> 课后思考
Q1:HTTP 协议允许在在请求行里使用完整的 URI,但为什么浏览器没有这么做呢?
A1:意义是一样的,整个请求都可以拿到完整的URI。
Q2:URI 的查询参数和头字段很相似,都是 key-value 形式,都可以任意自定义,那么它们在使用时该如何区别呢?
A2:先讲相同的,都是KV结构。再将不同的,第一、最明显的区别,查询参数,是跟整个URL一起出现的,而header如果不打开开发者模式,或者不抓包都看不到带了什么参数。第二、规则不同,头部字段不允许下划线、空格,查询字段key可以。补充:评论区老师答复“query参数针对的是资源(uri),而字段针对的是本次请求,也就是报文。一个是长期、稳定的,一个是短期、临时的。”
RFC标准把状态码分成了五类,用数字的第一位来表示,0~99不适用。
|> 状态码的种类
|> 开发中比较有价值的状态码详解:
|> 课后思考:
Q1:你在开发 HTTP 客户端,收到了一个非标准的状态码,比如 4××、5××,应当如何应对呢?
A1: 首先我会按照4、5先定义一个default的错误提示信息,4开头前端错了,就未知错误,5开头服务器错的,就服务器错误后面再试。
Q2:你在开发 HTTP 服务器,处理请求时发现报文里缺了一个必需的 query 参数,应该如何告知客户端错误原因呢?
A2:首先,报文错误,肯定是客户端的错误,所以是4开头的,具体错误信息,在body里面带上就好了吧,前端处理。
评论区收获:
1、约定body带json返回例如 {"code":-1,"message:"userid参数必须填写"}。
2、错误也可以是返回200,在body返回
|> 灵活拓展
Body不限制与文本格式得TXT或者HTML, 可以是图片、音频、视频等等....
|> 可靠传输
前面几章都讲到,浏览器访问一个网址是先经过TCP握手连接得,TCP本身就是以一个"可靠"的连接,但是不是100%数据一定能够发送到另一端,在网络繁忙的环境下,也有可能会收发失败。
|> 应用层协议
应用层协议有很多种,FTP、SMTP、SSH等等,他们的功能都是单一的,而HTTP几乎可以传递一切东西,满足各种需求。
|> 请求应答
通俗来讲就是"一收一发",契合传统的C\S系统架构,用轻量级的浏览器代替笨重的客户端,实现0维护瘦客户端。此外这种模式也很好的再RPC的工作模式下运作。
|> 无状态
TCP连接时会在双端各自维护一个状态类似,CLOSED、ESTABLISHED,形象的来讲,无状态就是没有记忆力,只要请求合法,都会返回一样的东西。对比UDP的无连接无状态,HTTP是有连接无状态,顺序发包顺序收包,按照收发顺序管理报文。
|> 其他
可压缩、分段获取数据、支持身份验证、支持国际化语言。
|> 课后思考
Q1:就如同开头我讲的那样,你能说一下今天列出的这些 HTTP 的特点中哪些是优点,哪些是缺点吗?
A1:刚开始以为拓展性高、可靠传输、无状态是优点。但是凡事都有正反面,因为你机制加多了,有可能就不灵活、效率不高,有时候机制少了,在某些场景下又可能不安全不可靠不稳定,所以没有绝得的优缺点,所以我个人认位灵活拓展那是它最大的优点了,只要大家都按照RPC来规范约束,可以愉快的写出轻便简洁的代码。
Q2:不同的应用场合有不同的侧重方面,你觉得哪个特点对你来说是最重要的呢?
A2:能够在上层实现的那些机制,都不算比较重要的,而是要找那种为什么是使我加上这种机制就能满足的基础,那才是最重要的,所以我绝得是灵活性
|> 优点
|> 优缺点
|> 课后思考
Q1:你最喜欢的 HTTP 优点是哪个?最不喜欢的缺点又是哪个?为什么?
Q2:你能够再进一步扩展或补充论述今天提到这些优点或缺点吗?
Q3:你能试着针对这些缺点提出一些自己的解决方案吗?
01| HTTP的实体数据
|> MIME(Multipupose Internet Main Extensions)
1、text:即文本,超文本 text/html,纯文本text/plain,样式表text/css
2、image:即图像文件,有image/gif 、 image\jpeg 、 image\png等
3、audio/video:音频和视频数据,例如audio/mpeg 、 video/mp4
4、application:数据格式不固定,可能是文本也可能是二进制,由上层来解析。常见的application/json、application/javascript、application/pdf、application/octet-stream
此外,有了数据类型,还不够,HTTP在传输的时候为了节约带宽,会进行压缩。所以还要告诉对方用什么类型的编码格式。用的"Encoding type"约定,常见的有:
1、gzip:GNU zip 压缩格式,也就是互联网上最流行的压缩格式
2、deflate:zlib(deflate)压缩格式,流行度仅次于gzip
3、br:一种专门为HTTP优化的新压缩算法
|> 数据类型使用的头字段
为了更好的客户端与服务端的“内容协商”,HTTP还定义了Accept请求头字段和Content实头字段。客户端用Accept告诉服务器想接受什么数据,而服务器用Content头告诉客户端实际发了什么数据。比如我们请求CSDN的官网
请求头:
响应头:
由图可知,每个类型可以用“,”来分割,此外,还有一个Accept-Encoding字段标记客户端支持的压缩格式。响应头则放在Content-Encoding里面。
|> 语言类型与编码
不同国家不同地区的人使用了很多不同的语言,HTTP为了解决这个问题,会在请求头带上“Accept-language”用于表示浏览器期望接收到什么国家地区的语言,并且除了语言种类,还可以支持到地区性的方言,以“type-subtype”的格式来表示。例如还是CSDN的官网,期望接收到汉语。当然了,我们也可以用UTF8、GBK等编码格式
|> 内容协商的质量值
在用那个Accept、Accept-Encoding、Accept-language的时候,还有用到一个特殊的参数“q”来表示权重。权重值UI大是1,最小是0.01,默认是1, 如果是0则表示拒绝,具体的形式如上图,“;” + "q= value"
|> 内容协商的结果
由于每个Web服务器使用的算法都不一样,所以要用一个字段来标记服务器在内容协商时参考的请求头字段,这个字段叫做“Vary”。
如图访问CDSN的网站返回的vary是 Accept-Encoding,意思就是依据这个字段来决定返回的响应报文。同一个URI可能又多个“版本”,主要用于传输链路中代理服务器实现缓存。
|> 动手实验
json文件的请求响应头
mp4文件的请求响应头
txt文件的请求响应头
webp文件的请求响应头
xml文件请求响应头
|> 课后思考
Q1、试着解释一下这个请求头“Accept-Encoding: gzip, deflate;q=1.0, *;q=0.5, br;q=0”,再模拟一下服务器的响应头。
A1:请求头哦表示的意思是,gzip = 权重1 ,deflate 权重也是1,其他所有的权重0.5, br这种压缩方式不合适。服务器响应头是,Content-Type + Content-Encoding = gzip\deflate\other , Content-Language,Vary:Accept-Encoding
Q2、假设你要使用 POST 方法向服务器提交一些 JSON 格式的数据,里面包含有中文,请求头应该是什么样子的呢?
A2:这题没想出来,看了评论区发现是在请求头带上一个Content-Type:application/json
发现原阿里Content-Type是实体字段,所以在请求也能带
Q3、试着用快递发货收货比喻一下 MIME、Encoding 等概念。
A3:
02| HTTP传输大文件
传输大文件的解决方案,把大文件变小,把大文件拆开变小。
|> 数据压缩
前面实体数据讲到,客户端发起请求头会带上一个Accept-Encoding字段,用于表示浏览器支持的报文压缩算法,服务器回复的Content-Encoding表示用了什么压缩方法,例如gzip,deflate,bar等来压缩。
如果压缩率有50%,相当于带宽不变的前提下,提升了一倍熟度。但是gzip压缩方法有压缩缺陷,之恶能对文本文件有较好的压缩率,图片、视频、音频本身就是高度压缩,有可能经过gzip后负负得正,报文还大了。
|> 分块传输
前面说了还可以把大文件拆散,在”Transfer-Encoding:chunked“来表示,意思是报文里的body部分,不是一次性发来的,而是被分成了许多快逐个发送。“Transfer-Encoding:chunked”与“Content-Length”这两个字段是互斥的,两个字段不能同时出现,长度要么已知,要么未知。
下面来剖析一下协议:
(PS:由于电脑的Telnet Server问题没法用Telnet看到报文)
|> 范围请求
HTTP中的范围请求可以让我们平时在日常看电影刷剧的过程中,一下跳到片头,一下跳到片尾。服务端必须在响应头使用字段“Accept-Ranges:bytes”,请求头中使用“Range”字段来表示,
客户端发起范围查询:
格式是,“bytes=x-y”, 范围从0开始计数,类似数组下标,比如文件100个字节,要获取前10个字节 "bytes = 0-9", 这里的格式跟Go语言中的切片有点像”bytes 10- “ 表示从第10个字节拿到最后一个,”bytes = -1“ 则表示获取最后一个字节。
服务端收到范围查询:
1、检查范围,错误返回416
2、获取偏移量数据,返回216
3、添加一个响应头 “Content - Range”,格式是“bytes x-y/length” ,这里会返回总长度
|> 分段传输
除了范围请求,HTTP还支持一次性获取多个片段数据。需要使用MIME类型:“multipart/bytesranges”表示报文是由多节字段序列组成的,还用加上一个“boundary = xxx”给出的段分割标记。
|> 课后思考
Q1、分块传输数据的时候,如果数据里含有回车换行(\r\n)是否会影响分块的处理呢?
A1:不会,因为每个分段里面都有指定长度
Q2、如果对一个被 gzip 的文件执行范围请求,比如“Range: bytes=10-19”,那么这个范围是应用于原文件还是压缩后的文件呢?
A2:看源文件是什么形式, 如果源文件是gzip则没问题,如果是一个普通的tx,那就是txt的数据。
03| HTTP连接管理
|> 短、长连接
短连接:发完HTTP协议就关闭TCP连接
长连接:保持TCP连接,要关的时候才关
|> 连接相关的字段
请求头里可以明确的指出要求使用长连接机制,使用字段是“Connection”,值为“keep-alive”。当然长连接也有他的弊端,由于需要一直保持长连接,所以有些连接会是浪费的,比如一直占用连接但是不发数据,数量多了会耗尽服务器的资源,一般会采取超时关闭,或者限量关闭的手段来解决。
|> 队头阻塞
|> 性能优化
并发连接:
一个客户端申请多个连接
域名分片:
做域名拆分,增大连接数
|> 课后思考
Q1、在开发基于 HTTP 协议的客户端时应该如何选择使用的连接模式呢?短连接还是长连接?
A1:里面的业务用长连接,大大减少连接开销。登录可以用短连接。
Q2、应当如何降低长连接对服务器的负面影响呢?
A2:1、限时
2、限流量
3、Linux配置半握手连接数
04| HTTP的重定向和跳转
|>重定向的过程
|>重定向的状态码
|>重定向的应用场景
|>重定向的相关问题
05| HTTP的Cookie
|>Cookie的工作过程
响应头字段:Set-Cookie,可以设置多个,用“;”隔开(例子:Set-Cookie:a=xxx \n Set-Cookie:b=xxx)
请求头字段:Cookie(例子:Cookie:a=xxx;b=yyy)
|>Cookie的属性
Set-Cookie:a = xxx;Max-age = 30;Expires = Fri,07...
|> Cookie的应用
|> 小结
|> 课后思考
1、如果 Cookie 的 Max-Age 属性设置为 0,会有什么效果呢?
答:Cookie失效
2、Cookie 的好处已经很清楚了,你觉得它有什么缺点呢?
答:由于是明文的存在,如果服务端没有做好一些加密、混淆等操作,而是直接用某些字符串给用户打标签,极其容易泄露用户的行为模型。
补充:
1、数量和大小限制,Cookie太大也不好,传输数据会大
2、客户端可能不保存Cookie,比如telnet收发数据,用户禁用浏览器保存Cookie的情况
06| HTTP的缓存控制
|> 服务器的缓存控制
|> 客户端的缓存控制
|> 条件请求
HTTP定义了以If开头的条件请求字段,第一次服务器返回的报文中需要带上Last-Modified、Etag,然后浏览器请求的时候就可以带上缓存的值去比较。
|> 小结
课下思考:
1、Cache 和 Cookie 都是服务器发给客户端并存储的数据,你能比较一下两者的异同吗?
答:Cache意思为资源保存,Cookie为标记主要是保存简要信息
2、即使有“Last-modified”和“ETag”,强制刷新(Ctrl+F5)也能够从服务器获取最新数据(返回 200 而不是 304),请你在实验环境里试一下,观察请求头和响应头,解释原因。
补充:强制刷新是因为请求头里面没有了条件请求的字段,所以服务器无法判断是否过期之类的,只能返回资源
07| HTTP的代理服务
|> 代理服务
在原本HTTP与服务器连接的过程中,中间多加一个节点,称之为代理服务器,代理服务器不产生内容,做转发用,转发上下游的请求和请求
|>代理的作用
|> 代理相关头字段
|> 代理协议
“X-Forwarded-For”由于在Http报文内,服务端每次获取源IP时还需要拆解协议,降低了性能,所以就出现了一个叫代理协议的标准。直接在HTTP报文前面多加一行ASCII码文本头,格式是
PROXY TCP4 1.1.1.1 2.2.2.2 55555 80\r\n
GET / HTTP/1.1\r\n
Host: www.xxx.com\r\n
\r\n
|> 小结:
|> 课后思考:
1、你觉得代理有什么缺点?实际应用时如何避免?
补充:
1、优点是匿名,多级代理还有做缓存的用途
2、 作为中转站,需要为上游和下游开启两个连接,大量并发请求,会出现性能瓶颈,应减少资源开销,加快响应速度,比如代理缓存,动静分离
2、你知道多少反向代理中使用的负载均衡算法?它们有什么优缺点?
答:轮询,哈希,一致性哈希
补充:
1、随机——简单,是否均匀看随机情况
2、轮询(一般轮询、加权轮询)——相对简单,也会考虑机器资源和性能的均衡性
3、哈希(一般哈希、一致性哈希、带虚拟节点的一致性哈希)——相对复杂,要求越公平就会越复杂,而且适当考虑了请求4、最少连接数、最快连接数
|>缓存代理服务
|>源服务器的缓存控制
|>客户端的缓存控制
|>其他问题
|> 小结
评论总结:
浏览器拿到一个网址的时候,先判断是否允许缓存,允许会先查看本地缓存:1.有缓存并在缓存可用期那直接拿来用。2.缓存不存在或者不可用 那需要请求。
浏览器拿到host,判断:1.ip+port 那直接请求对应的服务器 2.域名 那开展一系列的dns递归查询:先拿dns缓存,没有缓存->本地dns服务器->根dns服务器->顶级dns服务器->权威dns服务器->GSLB,查到ip返回最优ip组实现负载均衡,浏览器随机或者轮询取一个ip开始它的http请求之旅。
浏览器判断该网页是否允许缓存,然后添加Cache-Control的各种字段no-store是否允许缓存/no-cache缓存必须进行验证/noly-if-cached只接受代理的缓存等,max-age最大生存时间 max-stale 短时间过期可用 min-fresh 最短有效时间等。If-Modified-Since/if-None-Match/Last-modified/ETag等字段用于判断服务端是否有更新。然后将请求发给代理服务器。请求代理服务器,如果是第一次,要经历浏览器和代理服务器的3次tcp握手进行连接,连接成功,发送http请求。
代理服务器拿到请求,首先查看是否允许缓存,允许那就查看自己本地缓存有没有,通过查看max-age/max-stale/min-fresh等信息判断是否过期,没有过期直接拿来用,将数据返回给客户端。如果过期了,代理服务器将用客户端的请求,再次像真实服务器进行请求。如果也是第一次连接,需要经历代理服务器和真实服务器的3次tcp握手,连接成功,发送请求。
真实服务器收到请求之后,通过if-Modified-Since/Last-Modified/if-None-Match/ETag等字段判断是否有更新,没有更新,直接返回304。如果有更新,则将数据打包http response 返回。返回头字段会添加Cache-Control字段,用来判断缓存的控制策略以及生存周期,no-store不允许缓存/no-cache使用缓存必须先验证/must-revalidate缓存不过期可用过期必须重新请求验证/proxy-revalidate缓存过期只要求代理进行请求验证 private不能在代理层保存只能在客户端保存/public缓存完全开放 s-maxage缓存在代理上可以缓存的时间 no-transform不允许代理对缓存做任何的改动。然后根据业务需求判断该地址是不是需要重定向,如果需要是短期的重定向还是永久的重定向,按需将状态码修改为301或者302。最后真实服务器将数据打包成http相应 回给代理服务器。
代理服务器收到真实服务器的回应数据,首先会查看Cache-Control里的字段,是否允许它进行缓存,如果是private,代理服务器不进行缓存,直接返回给客户端。public则根据s-maxage/no-transform进行缓存,如果可以优化并且代理服务器需要优化,那可能会先优化数据,否则同时将数据回发给客户端。
客户端收到数据,如果是304,则直接拿缓存数据进行渲染,并修改相关缓存变量,比如时间,以及缓存使用策略。如果收到了301或者302,那么客户端会再次发起新的url请求,进行跳转到最终的页面。
最后,底层tcp 经过4次挥手,完成关闭连接。
|> 课后思考
1、加入了代理后 HTTP 的缓存复杂了很多,试着用自己的语言把这些知识再整理一下,画出有缓存代理时浏览器的工作流程图,加深理解。
答:如笔记内
2、缓存的时间策略很重要,太大太小都不好,你觉得应该如何设置呢?
答:根据缓存变化频率来设置,有规律根据规律走,没有规律不做缓存
01| HTTPS、SSL、TLS
|>为什么要有HTTPS
|>什么是安全?
|>什么是HTTPS
来一幅图讲解一下HTTP与HTTPS的区别:
|>SSL、TLS
SSL即安全套接层(Secure Sockets Layer),SSL在V3版本被IETF改名为TLS(传输层安全,Transport Layer Security),版本号从1.0重新算,所以TLS1.0实际上就是SSLV3.1。
|>OpenSSL
摘抄:
说到 TLS,就不能不谈到 OpenSSL,它是一个著名的开源密码学程序库和工具包,几乎支持所有公开的加密算法和协议,已经成为了事实上的标准,许多应用软件都会使用它作为底层库来实现 TLS 功能,包括常用的 Web 服务器 Apache、Nginx 等。OpenSSL 是从另一个开源库 SSLeay 发展出来的,曾经考虑命名为“OpenTLS”,但当时(1998 年)TLS 还未正式确立,而 SSL 早已广为人知,所以最终使用了“OpenSSL”的名字。OpenSSL 目前有三个主要的分支,1.0.2 和 1.1.0 都将在今年(2019)年底不再维护,最新的长期支持版本是 1.1.1,我们的实验环境使用的 OpenSSL 是“1.1.0j”。由于 OpenSSL 是开源的,所以它还有一些代码分支,比如 Google 的 BoringSSL、OpenBSD 的 LibreSSL,这些分支在 OpenSSL 的基础上删除了一些老旧代码,也增加了一些新特性,虽然背后有“大金主”,但离取代 OpenSSL 还差得很远。
|>小结
|>课后思考
1、你能说出 HTTPS 与 HTTP 有哪些区别吗?
答:传输层的不同
2、你知道有哪些方法能够实现机密性、完整性等安全特性呢?
补充:实现机密性可以采用加密手段,接口签名实现完整性,数字签名用于身份认证
02| 对称加密和非堆成加密
|>对称加密
对称加密很好理解,就是加、解密都是用一个密钥
TLS有非常多的对称加密算法可以提供,比如 RC4、DES、3DES、AES、ChaCha20 等,但前三种算法都被认为是不安全的,通常都禁止使用,目前常用的只有 AES 和 ChaCha20。
|>加密分组模式
|>非对称加密
对称加密无法解决被窃取密钥从而解密密文的方法,所以出现了非对称加密(公钥加密算法)
|>混合加密
由于非对称的加解密设计到数学公式,那么会比较消耗双方计算性能,跟对称加密是相差几百倍,所以出现了混合加密。
混合加密采用了,首次交换对称加密密钥的时候,把对称加密密钥当作报文用非对称加密的方法加密,等建立了连接以后,就用这个随机生成的对称加密密钥来加密报文,因为这个过程中的对称加密密钥是加密过的,就算截取了也无法解出,所以更加解不出后面对称加密加密过的报文,从而保密了数据。
|>小结
|>课后思考
1、在混合加密中用到了公钥加密,因为只能由私钥解密。那么反过来,私钥加密后任何人都可以用公钥解密,这有什么用呢?
答:私钥加密过后的数据,公钥才能打开,证明这个协议确实是下发公钥过来的那个人,而不是其他人
03| 数字签名与证书
只有对报文加密是不够的,一方面是黑客可以搜集尽量多的报文,去试探服务器的响应,再获取进一步的线索,最后破解明文。或者是下发的公钥根本就不是源服务器或代理服务器的,而是黑客建立的钓鱼网站,你以为你在跟某人聊天,其实不是,那个只是戴上头套的黑客(碟中谍)。
|>摘要算法
|>完整性
有了摘要,如果消息在传输过程中被修改,那么数据的摘要一定是不一样的,如果把摘要不具有机密性的话,那么很可能会把摘要也改了,所以摘要也要做机密性。如图所示
|>数字签名
有了以上的这些手段,还是很可能有漏洞,除了能伪造网站,还能伪造用户,向服务端发请求,所以客户端必须证明自己是自己,所以这里要用数字签名。
和网站互换公钥,然后我用自己的私钥签名消息,网站收到后用我的公钥来验签,以此来证明我是我。
|>数字证书与CA
任何的人都可以生成公钥,所以怎么证明这个公钥就是某权威网站的呢,这里就用到了CA
|>证书体系的弱点
|>小节
|>课后思考
1、为什么公钥能够建立信任链,用对称加密算法里的对称密钥行不行呢?
答:不可以,因为在一开始交换对称密钥的时候有可能泄露密钥。私钥加密,公钥解密能证明我是我
2、假设有一个三级的证书体系(Root CA=> 一级 CA=> 二级 CA),你能详细解释一下证书信任链的验证过程吗?
补充:
一、具体流程大概是:
1、服务器去CA机构申请证书,证书中包含了要发给客户端的公钥、签发者、到期时间等等信息。如果这样简单地把证书发给浏览器,中间人可以轻松地修改成自己的公钥,之后的通信就是不安全的了。于是需要一定的加密手段,这里的做法就是使用数字签名:将证书的信息利用摘要算法计算出摘要之后,用CA的秘钥进行加密,生成数字签名。
2、服务器将数字证书和数字签名一起发给浏览器,因为有数字签名,所以数字证书无法被中间人做修改(修改之后生成的数字签名无法被CA公钥解密),浏览器拿到数字证书之后,去本地的信任机构中查询到对应的机构,利用其公钥解密数字签名,验证证书是否有被修改过。这一步就保证了浏览器获取到的公钥一定是正确的。
3、公钥正确地传给浏览器之后,接着就是协商对称加密的密钥,然后通信等等..二、服务器返回的是证书链(不包括根证书,根证书预置在浏览器中),然后浏览器就可以使用信任的根证书(根公钥)解析证书链的根证书得到一级证书的公钥+摘要验签,然后拿一级证书的公钥解密一级证书拿到二级证书的公钥和摘要验签,再然后拿二级证书的公钥解密二级证书得到服务器的公钥和摘要验签,验证过程就结束了。
04| TLS1.2\1.3
|>TLS协议组成
|>抓包准备工作
目前是直接wireshark过滤tls的协议
|>ECDHE握手过程
|>RSA握手过程
|>双向认证
|>TLS1.3
|>最大化兼容性
由于1.1、1.2版本已经推出了很多年,所以改造很困难,所以TLS1.3不得不向下兼容,用拓展协议在末尾添加一系列的拓展字段来增加新的功能,握手的hello消息后面必须有supported_versions,标记TLS版本号区分新旧协议。
|>强化安全
废除了许多加密算法,禁用了加密,使得TLS1.3更轻量,为什么不用RSA算法加密,都用ECDHE,是为了防止今日截获,明日破解的状况,一但RSA加密被破戒了,获取了pre master,那么以往的所有信息都将泄露。
|>提升性能
TLS1.3比TLS1.2减少了一个RTT,删除了“key-exchange”,在hello把需要的椭圆曲线、签名算法、公钥带上
|>小节
|>课后思考
1、密码套件里的那些算法分别在握手过程中起了什么作用?
2、你能完整地描述一下 RSA 的握手过程吗?
3、你能画出双向认证的流程图吗?
4、TLS1.3 里的密码套件没有指定密钥交换算法和签名算法,那么在握手的时候会不会有问题呢?
答:TLS1.3精简了加密算法,通过support_groups、key_share、signature_algorithms这些参数就能判断出密钥交换算法和签名算法,不用在cipher suite中协商了
5、结合上一讲的 RSA 握手过程,解释一下为什么 RSA 密钥交换不具有“前向安全”。
答:一次破解终生免费
6、TLS1.3 的握手过程与 TLS1.2 的“False Start”有什么异同?
答:相同点:都在未收到Finished确认消息时就已经向对方发送加密信息了,不同点:TLS1.3将change cipher spec合并到了hello中
05| HTTPS优化
*待完成的篇幅:
06| HTTPS使用场景
01| Nginx
02| OpenResty
03| WAF
04| CDN
05| WebSocket
01| HTTP性能优化