推荐一下极客时间的《透视HTTP协议》,记录专栏中一些比较重要的点。如有侵权,请联系我。
开篇词
To Be a HTTP Hero
破冰篇
时势与英雄:HTTP的前世今生
讲解了HTTP发展的趋势 从HTTP 0.9到HTTP1.0(不作为正式使用)到HTTP1.1 (现在主流)到HTTP2 (2014产生)到HTTP3(QUIC协议推动发展) HTTP2和HTTP3主要是由谷歌需求推动协议发展。
HTTP0.9
- 采用纯文本形式
- 只允许使用GET获取资源,获得后就断开连接
HTTP1.0
- 增加了 HEAD、POST 等新方法;
- 增加了响应状态码,标记可能的错误原因;
- 引入了协议版本号概念;
- 引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活;
- 传输的数据不再仅限于文本。
HTTP1.1
- 增加了 PUT、DELETE 等新的方法;
- 增加了缓存管理和控制;
- 明确了连接管理,允许持久连接;
- 允许响应数据分块(chunked),利于传输大文件;
- 强制要求 Host 头,让互联网主机托管成为可能。
缓存管理和控制:当浏览器获得资源后,服务器回传资源有效时间,浏览器将参数放在Cache-Control中下次请求时判断缓存是否过期再次请求
HTTP2
- 二进制协议,不再是纯文本;
- 可发起多个请求,废弃了 1.1 里的管道;
- 使用专用算法压缩头部,减少数据传输量;
- 允许服务器主动向客户端推送数据;
- 增强了安全性,“事实上”要求加密通信。
HTTP3
HTTP是什么?HTTP又不是什么?
HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
HTTP世界全览(上):与HTTP相关的各种概念
- 互联网上绝大部分资源都使用 HTTP 协议传输;
- 浏览器是 HTTP 协议里的请求方,即 User Agent;
- 服务器是 HTTP 协议里的应答方,常用的有 Apache 和 Nginx;
- CDN 位于浏览器和服务器之间,主要起到缓存加速的作用;
- 爬虫是另一类 User Agent,是自动访问网络资源的程序。
HTTP世界全览(下):与HTTP相关的各种协议
代理的作用
- 负载均衡:把访问请求均匀分散到多台机器,实现访问集群化;
- 内容缓存:暂存上下行的数据,减轻后端的压力;
- 安全防护:隐匿 IP, 使用 WAF 等工具抵御网络攻击,保护被代理的机器;
- 数据处理:提供压缩、加密等额外的功能。
常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?
TCP是有状态的协议,发送数据前双方必须建立连接,由此可以保证传输字节流 是连续的而且没有重复。UDP是没有状态的协议,发送前不需要建立连接。UDP发送的数据包是无序的,且乱序收的。
CDN处于应用层 (一开始以为处于网络层,果然对于请求处理层数越少越好)
域名里有哪些门道
- 域名使用字符串来代替 IP 地址,方便用户记忆,本质上一个名字空间系统;
- DNS 就像是我们现实世界里的电话本、查号台,统管着互联网世界里的所有网站,是一 个“超级大管家”;
- DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存;
- 使用 DNS 可以实现基于域名的负载均衡,既可以在内网,也可以在外网。
DNS域名解析的过程可以分别为本地host文件-> 本地域名服务器->根域名服务器->权威域名服务器
外围有多级缓存为大公司为了加速域名解析,会创建自己的DNS域名服务器,非权威域名服务器。作为用户DNS查询的代理,代替用户访问核心DNS。如同谷歌创建的8.8.8.8免费公共域名服务器。
自己动手,搭建HTTP实验环境
配置实验环境 ,同时安装了wireshak以及openresty
基础篇
键入网址再按下回车,后面究竟发生了什么?
再简要叙述一下这次最简单的浏览器 HTTP 请求过程:
- 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;
- 浏览器用 TCP 的三次握手与服务器建立连接;
- 浏览器向服务器发送拼好的报文;
- 服务器收到报文后处理请求,同样拼好报文再发给浏览器;
- 浏览器解析报文,渲染输出页面。
HTTP报文是什么样子的?
HTTP协议主要由以下三部分构成
- 起始行
- 头部字段集合
- 消息正文
HTTP协议再细分可以分为 请求以及响应
请求行包括
- 请求方法
- 请求目标
- HTTP协议版本号
这三个部分通常用空格来进行隔开,最后用CRLF来表示结束
状态行包括
- HTTP协议版本
- 状态码
- 原因 (如ok等)
头部字段主要分为四大类
- 通用字段:在请求头和响应头里都可以出现;
- 请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;
- 响应字段:仅能出现在响应头里,补充说明响应报文的信息;
- 实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。
请求字段:
Host字段:告诉服务器这个请求应该由哪个主机来处理
User-Agent字段:告诉服务器请求的客户端信息
通用字段:
Data字段:客户端可以使用这个时间再搭配其他字段决定缓存策略
响应字段:
Server字段:告诉客户端 响应服务器信息(也有部分网站不用透露信息)
实体字段:
content-length:表示响应体中报文body的长度
总结
- HTTP 报文结构就像是“大头儿子”,由“起始行 + 头部 + 空行 + 实体”组成,简单地说就是“header+body”;
- HTTP 报文可以没有 body,但必须要有 header,而且 header 后也必须要有空行,形象地说就是“大头”必须要带着“脖子”;
- 请求头由“请求行 + 头部字段”构成,响应头由“状态行 + 头部字段”构成;
- 请求行有三部分:请求方法,请求目标和版本号;
- 状态行也有三部分:版本号,状态码和原因字符串;
- 头部字段是 key-value 的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;
- HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。
应该如何理解请求方法?
HTTP/1.1 规定了八种方法
- GET:获取资源,可以理解为读取或者下载数据;
- HEAD:获取资源的元信息;
- POST:向资源提交数据,相当于写入或上传数据;
- PUT:类似 POST;
- DELETE:删除资源;
- CONNECT:建立特殊的连接隧道;
- OPTIONS:列出可对资源实行的方法;
- TRACE:追踪请求 - 响应的传输路径。
GET POST DELETE PUT 不用过多介绍
HEAD
HEAD方法与 GET 方法类似,也是请求从服务器获取资源,服务器的处理机制也是一样的,但服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”。
HEAD 方法可以看做是 GET 方法的一个“简化版”或者“轻量版”。因为它的响应头与 GET 完全相同,所以可以用在很多并不真正需要资源的场合,避免传输 body 数据的浪费。
安全与幂等
对于安全性来说GET和HEAD是安全的,不会修改计算机的资源。剩下三种会修改或者删除计算机的资源所以不是安全的。
对于幂等性来说GET和HEAD是幂等的。同时PUT DELETE方法也是幂等的,多次修改一条记录最后的结果也是一条,而POST则会修改数据的个数 不是幂等的。
总结:
- 请求方法是客户端发出的、要求服务器执行的、对资源的一种操作;
- 请求方法是对服务器的“指示”,真正应如何处理由服务器来决定;
- 最常用的请求方法是 GET 和 POST,分别是获取数据和发送数据;
- HEAD 方法是轻量级的 GET,用来获取资源的元信息;
- PUT 基本上是 POST 的同义词,多用于更新数据;
- “安全”与“幂等”是描述请求方法的两个重要属性,具有理论指导意义,可以帮助我们设计系统。
你能写出正确的网址吗?
URI,也就是统一资源标识符(Uniform Resource Identifier)
URL——统一资源定位符(Uniform Resource Locator)
URL 实在是太普及了,所以常常把这两者简单地视为相等。
URL组成的基本格式
浏览器会根据cheme使用默认的端口号 (HTTP 80 端口,HTTPS 443端口)
总结
- URI 是用来唯一标记服务器上资源的一个字符串,通常也称为 URL;
- URI 通常由 scheme、host:port、path 和 query 四个部分组成,有的可以省略;
- scheme 叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问;
- “host:port”表示资源所在的主机名和端口号;
- path 标记资源所在的位置;
- query 表示对资源附加的额外要求;
- 在 URI 里对“@&/”等特殊字符和汉字必须要做编码,否则服务器收到 HTTP 报文后会无法正确处理。
响应状态码该怎么用?
状态码的分类为
- 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
- 2××:成功,报文已经收到并被正确处理;
- 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
- 4××:客户端错误,请求报文有误,服务器无法处理;
- 5××:服务器错误,服务器在处理请求时内部发生了错误。
1××
1××类状态码属于提示信息,是协议处理的中间状态,实际能够用到的时候很少。
2××
2××类状态码表示服务器收到并成功处理了客户端的请求,这也是客户端最愿意看到的状态码。
“200 OK”是最常见的成功状态码,表示一切正常,服务器如客户端所期望的那样返回了处理结果,如果是非 HEAD 请求,通常在响应头后都会有 body 数据。
“204 No Content”是另一个很常见的成功状态码,它的含义与“200 OK”基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的。
“206 Partial Content”是 HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,它与 200 一样,也是服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。
3××
3××类状态码表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源,也就是通常所说的“重定向”,包括著名的 301、302 跳转。
“301 Moved Permanently”俗称“永久重定向”,含义是此次请求的资源已经不存在了,需要改用改用新的 URI 再次访问。
与它类似的是“302 Found”,曾经的描述短语是“Moved Temporarily”,俗称“临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问。
4××
4××类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了。
“400 Bad Request”是一个通用的错误码,表示请求报文有错误,但具体是数据格式错误、缺少请求头还是 URI 超长它没有明确说,只是一个笼统的错误,
“403 Forbidden”实际上不是客户端的请求出错,而是表示服务器禁止访问资源。原因可能多种多样,例如信息敏感、法律禁止等,如果服务器友好一点
“404 Not Found”可能是我们最常看见也是最不愿意看到的一个状态码,它的原意是资源在本服务器上未找到
5××
5××类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”。
“500 Internal Server Error”与 400 类似,也是一个通用的错误码
“501 Not Implemented”表示客户端请求的功能还不支持
“502 Bad Gateway”通常是服务器作为网关或者代理时返回的错误码
“503 Service Unavailable”表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503
总结
- 状态码在响应报文里表示了服务器对请求的处理结果;
- 状态码后的原因短语是简单的文字描述,可以自定义;
- 状态码是十进制的三位数,分为五类,从 100 到 599;
- 2××类状态码表示成功,常用的有 200、204、206;
- 3××类状态码表示重定向,常用的有 301、302、304;
- 4××类状态码表示客户端错误,常用的有 400、403、404;
- 5××类状态码表示服务器错误,常用的有 500、501、502、503。
HTTP有哪些特点?
总结
- HTTP 是灵活可扩展的,可以任意添加头字段实现任意功能;
- HTTP 是可靠传输协议,基于 TCP/IP 协议“尽量”保证数据的送达;
- HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据;
- HTTP 使用了请求 - 应答模式,客户端主动发起请求,服务器被动回复请求;
- HTTP 本质上是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。
HTTP虽然是可靠的传输协议但不保证传输的时候是完全有效的,想要完全可靠,需要使用中间件消息队列等。
HTTP有哪些优点?又有哪些缺点?
总结
- HTTP 最大的优点是简单、灵活和易于扩展;
- HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施;
- HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”;
- HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听;
- HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改;
- HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间。
进阶篇
海纳百川:HTTP的实体数据(干货)
数据类型和压缩
当请求返回的时候,TCP和IP任务已经完成但是HTTP需要解析出响应文件的类型。同时HTTP文件内容在传输时候经常会有压缩。因此产生数据类型和压缩类型的需求。
HTTP支持压缩类型有:
- gzip:GNU zip 压缩格式,也是互联网上最流行的压缩格式;
- deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip;
- br:一种专门为 HTTP 优化的新压缩算法(Brotli)。
HTTP常见数据类型有:
- text:即文本格式的可读数据,我们最熟悉的应该就是 text/html 了,表示超文本文档,此外还有纯文本 text/plain、样式表 text/css 等。
- image:即图像文件,有 image/gif、image/jpeg、image/png 等。
- audio/video:音频和视频数据,例如 audio/mpeg、video/mp4 等。
- application:数据格式不固定,可能是文本也可能是二进制,必须由上层应用程序来解释。常见的有 application/json,application/javascript、application/pdf 等,另外,如果实在是不知道数据是什么类型,像刚才说的“黑盒”,就会是 application/octet-stream,即不透明的二进制数据。
HTTP 协议为此定义了两个 Accept 请求头字段和两个 Content 实体头字段,用于客户端和服务器进行“内容协商”。也就是说,客户端用 Accept 头告诉服务器希望接收什么样的数据,而服务器用 Content 头告诉客户端实际发送了什么样的数据。
语言类型与编码
为了解决浏览器能够解析出正确的语言。为此引入了语言类型和编码。
Accept-language:指定了用户使用想要使用的语言类型 (可有多个参数)
Accept-Language: zh-CN, zh, en
Content-Language:返回浏览器的语言类型
Content-Language: zh-CN
字符集在 HTTP 里使用的请求头字段是Accept-Charset,但响应头里却没有对应的 Content-Charset,而是在Content-Type字段的数据类型后面用“charset=xxx”来表示,这点需要特别注意。
总结
- 数据类型表示实体数据的内容是什么,使用的是 MIME type,相关的头字段是 Accept 和 Content-Type;
- 数据编码表示实体数据的压缩方式,相关的头字段是 Accept-Encoding 和 Content-Encoding;
- 语言类型表示实体数据的自然语言,相关的头字段是 Accept-Language 和 Content-Language;
- 字符集表示实体数据的编码方式,相关的头字段是 Accept-Charset 和 Content-Type;
- 客户端需要在请求头里使用 Accept 等头字段与服务器进行“内容协商”,要求服务器返回最合适的数据;
- Accept 等头字段可以用“,”顺序列出多个可能的选项,还可以用“;q=”参数来精确指定权重。
HTTP传输大文件的方法
主要方法有两种,压缩以及分块传输
压缩的三种算法中gzip压缩率可以达到百分之60,而br算法对于HTML文件压缩效率在gzip基础上还可以提升百分之20。
分块传输(重点)
若使用分块传输那么响应报文会添加Transfer-Encoding以及Content-length。“Transfer-Encoding: chunked”和“Content-Length”这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked)。
范围请求
HTTP 协议为了满足视频跳点观看的需求,提出了“范围请求”(range requests)的概念,范围请求不是 Web 服务器必备的功能,可以实现也可以不实现,所以服务器必须在响应头里使用字段“Accept-Ranges: bytes”明确告知客户端:“我是支持范围请求的”。
排队也要讲效率:HTTP的连接管理
主要内容短连接 长连接 队头阻塞
短连接
短连接对应版本为HTTP0.9 指使用HTTP进行通信时,两者每次传送数据都要建立TCP连接,短连接的缺点严重制约了服务器的服务能力。
长连接
对于短连接的缺陷,HTTP1.1提出多次请求只需建立一次TCP连接,减少服务器的消耗。使用的字段是Connection,值是“keep-alive”。长时间的空闲连接也会占据服务器的资源,所以长连接也需要在适当的时间关闭。通常有两种方式来在适当时间关闭请求,在一定请求后关闭连接 在设定空闲时间内无请求关闭连接
队头阻塞
队头阻塞主要是因为网络模型为“请求-应答”模型。前面的未响应请求对阻塞后方请求。对于HTTP来说可以使用 并发连接来解决,对于同一个域名建立多个连接。(多个连接会加剧服务器资源消耗被服务器当成攻击拒绝连接)
总结
- 早期的 HTTP 协议使用短连接,收到响应后就立即关闭连接,效率很低;
- HTTP/1.1 默认启用长连接,在一个连接上收发多个请求响应,提高了传输效率;
- 服务器会发送“Connection: keep-alive”字段表示启用了长连接;
- 报文头里如果有“Connection: close”就意味着长连接即将关闭;
- 过多的长连接会占用服务器资源,所以服务器会用一些策略有选择地关闭长连接;
- “队头阻塞”问题会导致性能下降,可以用“并发连接”和“域名分片”技术缓解。
HTTP的重定向和跳转(干货)
在网页中由用户主动发起请求的跳转称为 主动跳转,用户无法控制的称为 被动跳转 ,同时也被称为 重定向
这里出现了一个新的头字段“Location: /index.html”,它就是 301/302 重定向跳转的秘密所在。
“Location”字段属于响应字段,必须出现在响应报文里。但只有配合 301/302 状态码才有意义,它标记了服务器要求重定向的 URI。
对于站内的链接可以使用 相对URl 站外的链接必须使用 绝对URI
301 以及 302
在重定向状态码中重用的分别为301以及302。 301称为“永久重定向” 302称为“临时重定向” 。
永久重定向指当运行服务器进行更新以及修改,资源位置完全改变时使用
临时重定向指当系统进行维修或者在服务降级时进行调用
对于浏览器来说 永久和临时的区别在于对于永久性的重定向,浏览器下次该地址时会进行优化。对于临时,浏览器在下次访问的时候只会认为该地址暂时无法使用,下次请求时仍会使用原来URL。
HTTP的Cookie机制(干货)
HTTP增加Cookie是为了解决HTTP是无状态连接的问题。为此HTTP中增加响应头字段Set-Cookie和请求头字段Cookie。Cookie是存储在客户端也就是浏览器中,只在本浏览器内生效。
在Cookie中也可以设置其他cookie属性如cookie过期时间,可以使用 Expires 和 Max-Age 两个属性来设置。
Expires为绝对过期时间,为某个绝对时间点。 Max-Age为相对过期时间在某个时间点上延长一定时间。浏览器会优先使用 Max-Age作为过期的时间。
对于cookie的安全性,可以使用另一个属性“SameSite”防范“跨站请求伪造”(XSRF)攻击。属性“HttpOnly”会告诉浏览器,此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问。
总结
- Cookie 是服务器委托浏览器存储的一些数据,让服务器有了“记忆能力”;
- 响应报文使用 Set-Cookie 字段发送“key=value”形式的 Cookie 值;
- 请求报文里用 Cookie 字段发送多个 Cookie 值;
- 为了保护 Cookie,还要给它设置有效期、作用域等属性,常用的有 Max-Age、Expires、Domain、HttpOnly 等;
- Cookie 最基本的用途是身份识别,实现有状态的会话事务。
生鲜速递:HTTP的缓存控制(干货)
这篇文章感觉比较干货,建议看原文
服务器有缓存,浏览器也有缓存。缓存有什么作用,又是通过哪几个字段来保证有效,就是这篇文章的所有内容。
当使用浏览器的前进或者后退的时候,这时使用了缓存。在缓存期内浏览器有时仍会请求服务器获取资源,因为缓存的使用是服务器和浏览器协商的结果。
缓存的字段有如下几个
-
max-age:缓存使用的最大有效时间,注意max-age为ttl(time to live)当服务器响应时开始计时;
-
no_store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;
-
no_cache:它的字面含义容易与 no_store 搞混,实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本;
-
must-revalidate:又是一个和 no_cache 相似的词,它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证。
对于后两种验证缓存的类型,HTTP采用条件请求字段,将缓存的判断放在服务端进行处理,由此来避免两次请求占用网络带宽。
条件请求一共有 5 个头字段,我们最常用的是“if-Modified-Since”和“If-None-Match”这两个。需要第一次的响应报文预先提供“Last-modified”和“ETag”,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。(看原文)
总结
- 缓存是优化系统性能的重要手段,HTTP 传输的每一个环节中都可以有缓存;
- 服务器使用“Cache-Control”设置缓存策略,常用的是“max-age”,表示资源的有效期;
- 浏览器收到数据就会存入缓存,如果没过期就可以直接使用,过期就要去服务器验证是否仍然可用;
- 验证资源是否失效需要使用“条件请求”,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以复用缓存里的资源;
- 验证资源是否被修改的条件有两个:“Last-modified”和“ETag”,需要服务器预先在响应报文里设置,搭配条件请求使用;
- 浏览器也可以发送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新数据。
良心中间商:HTTP的代理服务
代理的主要作用:
- 负载均衡:将请求分发都不同后端服务机器。
- 健康检查:使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用;
- 安全防护:保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载;
- 加密卸载:对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本;
- 数据过滤:拦截上下行的数据,任意指定策略修改请求或者响应;
- 内容缓存:暂存、复用服务器响应。
代理相关头字段:
Via:标明代理的身份,追加代理用户的主机名或者域名。
X-Forwarded-For:每经过一个代理节点就会在字段里追加一个信息。追加的是代理主机的IP。
X-Real-IP:记录客户端 IP 地址,没有中间的代理信息,相当于是“X-Forwarded-For”的简化版。
从抓包里就可以清晰地看出代理与客户端、源服务器的通信过程:
- 客户端 55061 先用三次握手连接到代理的 80 端口,然后发送 GET 请求;
- 代理不直接生产内容,所以就代表客户端,用 55063 端口连接到源服务器,也是三次握手;
- 代理成功连接源服务器后,发出了一个 HTTP/1.0 的 GET 请求;
- 因为 HTTP/1.0 默认是短连接,所以源服务器发送响应报文后立即用四次挥手关闭连接;
- 代理拿到响应报文后再发回给客户端,完成了一次代理服务。
总结:
- HTTP 代理就是客户端和服务器通信链路中的一个中间环节,为两端提供“代理服务”;
- 代理处于中间层,为 HTTP 处理增加了更多的灵活性,可以实现负载均衡、安全防护、数据过滤等功能;
- 代理服务器需要使用字段“Via”标记自己的身份,多个代理会形成一个列表;
- 如果想要知道客户端的真实 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”;
- 专门的“代理协议”可以在不改动原始报文的情况下传递客户端的真实 IP。
HTTP的缓存代理
这篇个人认为是涨知识的一篇文章
总结
- 计算机领域里最常用的性能优化手段是“时空转换”,也就是“时间换空间”或者“空间换时间”,HTTP 缓存属于后者;
- 缓存代理是增加了缓存功能的代理服务,缓存源服务器的数据,分发给下游的客户端;
- “Cache-Control”字段也可以控制缓存代理,常用的有“private”“s-maxage”“no-transform”等,同样必须配合“Last-modified”“ETag”等字段才能使用;
- 缓存代理有时候也会带来负面影响,缓存不良数据,需要及时刷新或删除。
安全篇
HTTPS是什么?SSL/TLS又是什么?
因为 HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,其中的“HTTP”和“TCP/IP”我们都已经明白了,只要再了解一下 SSL/TLS,HTTPS 也就能够轻松掌握。
SSL 的全称是“Secure Socket Layer”,由网景公司发明,当发展到 3.0 时被标准化,改名为 TLS,即“Transport Layer Security”,但由于历史的原因还是有很多人称之为 SSL/TLS,或者直接简称为 SSL。
SSL 使用了许多密码学最先进的研究成果,综合了对称加密、非对称加密、摘要算法、数字签名、数字证书等技术,能够在不安全的环境中为通信的双方创建出一个秘密的、安全的传输通道,为 HTTP 套上一副坚固的盔甲。
因为HTTP明文传输的不安全所以在原先HTTP运行的TCP/IP层上面添加了一层TLS/SSL来确保安全性。
安全性主要包括以下四个方面
- 机密性
- 完整性
- 身份认证
- 不可否认
SSL最初在1994年由网景公司提出,后在1999年改名为TSL。目前广泛使用的协议是TSL1.2。
TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。
TLS 的密码套件命名非常规范,格式很固定。基本的形式是“密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法”
“握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数。”
总结
- 因为 HTTP 是明文传输,所以不安全,容易被黑客窃听或窜改;
- 通信安全必须同时具备机密性、完整性,身份认证和不可否认这四个特性;
- HTTPS 的语法、语义仍然是 HTTP,但把下层的协议由 TCP/IP 换成了 SSL/TLS;
- SSL/TLS 是信息安全领域中的权威标准,采用多种先进的加密技术保证通信安全;
- OpenSSL 是著名的开源密码学工具包,是 SSL/TLS 的具体实现。
固若金汤的根本(上):对称加密与非对称加密
实现机密性最常用的手段是“加密”(encrypt),就是把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊“钥匙”的人才能再转换出原始文本。
这里的“钥匙”就叫做“密钥”(key),加密前的消息叫“明文”(plain text/clear text),加密后的乱码叫“密文”(cipher text),使用密钥还原明文的过程叫“解密”(decrypt),是加密的反操作,加密解密的操作过程就是“加密算法”。
加密可以分为两大类:对称加密和非对称加密。
对称加密
“对称加密”很好理解,就是指加密和解密时使用的密钥都是同一个,是“对称”的。只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。
对称加密的算法主要由AES以及ChaCha20 。
加密分组模式
对称算法还有一个“分组模式”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密(即密钥)转化为大秘密(即密文)。
非对称加密
对称加密看上去好像完美地实现了机密性,但其中有一个很大的问题:如何把密钥安全地传递给对方,术语叫“密钥交换”。
非对称加密的算法主要有RSA和ECC。
混合加密
由于非对称加密经常使用数学方法进行加密解密,所以计算时间较长。对称加密时间则比非对称加密速度快好几个量级。所以TSL使用混合加密。
在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题。
然后用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。
对方拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。
总结
- 加密算法的核心思想是“把一个小秘密(密钥)转化为一个大秘密(密文消息)”,守住了小秘密,也就守住了大秘密;
- 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换,常用的有 AES 和 ChaCha20;
- 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢,常用的有 RSA 和 ECC;
- 把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密,也就是 TLS 里使用的加密方式。
固若金汤的根本(下):数字签名与证书
实现完整性的手段主要是摘要算法(Digest Algorithm),也就是常说的散列函数、哈希函数(Hash Function)。
摘要算法使得丝毫不同的内容产生的结果也是完全不同,TLS推荐使用的摘要算法主要是 SHA-2 , MD5以及SHA-1由于算法的安全性不足 ,在TLS中被禁用。
真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息和摘要,这样黑客无法得知明文,也就没有办法动手脚了。
数字签名
非对称加密里的“私钥”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。
数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。
但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。
签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。
数字证书和 CA
我们常说的CA(Certificate Authority,证书认证机构)。它就像网络世界里的公安局、教育部、公证中心,具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。
CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。
总结
- 摘要算法用来实现完整性,能够为数据生成独一无二的“指纹”,常用的算法是 SHA-2;
- 数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;
- 公钥的分发需要使用数字证书,必须由 CA 的信任链来验证,否则就是不可信的;
- 作为信任链的源头 CA 有时也会不可信,解决办法有 CRL、OCSP,还有终止信任。
飞翔篇
时代之风(上):HTTP/2特性概览
头部压缩
由于报文请求头一般都会携带许多固定的头字段,而请求体的内容往往只有很少同时多次重复的请求使得重复的头部字段被多次发送,所以HTTP2开发出专门的压缩算法进行头部压缩,由于gzip算法会被”crime“攻击所以HTTP2开发了专门的“HPACK”算法,在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还釆用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。
二进制格式
由于传统的纯文本形式会使用复杂的状态机,导致文本解析效率低。HTTP2采用二进制来优化,将原来的的“Header+Body”的消息“打散”为数个小片的二进制“帧”(Frame),用“HEADERS”帧存放头数据、“DATA”帧存放实体数据。
虚拟的“流”
HTTP/2 为此定义了一个“流”(Stream)的概念,它是二进制帧的双向传输序列,同一个消息往返的帧会分配一个唯一的流 ID。通过流ID来组装分散的二进制帧,因为“流”是虚拟的,实际上并不存在,所以 HTTP/2 就可以在一个 TCP 连接上用“流”同时发送多个“碎片化”的消息,这就是常说的“多路复用”( Multiplexing)——多个往返通信都复用一个连接来处理。
推送模式
HTTP/2 还在一定程度上改变了传统的“请求 - 应答”工作模式,服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。比如,在浏览器刚请求 HTML 的时候就提前把可能会用到的 JS、CSS 文件发给客户端,减少等待的延迟,这被称为“服务器推送”(Server Push,也叫 Cache Push)。
强化安全
互联网上通常所能见到的 HTTP/2 都是使用“https”协议名,跑在 TLS 上面。
为了区分“加密”和“明文”这两个不同的版本,HTTP/2 协议定义了两个字符串标识符:“h2”表示加密的HTTP/2,“h2c”表示明文的 HTTP/2,多出的那个字母“c”的意思是“clear text”。
协议栈
小结:
- HTTP 协议取消了小版本号,所以 HTTP/2 的正式名字不是 2.0;
- HTTP/2 在“语义”上兼容 HTTP/1,保留了请求方法、URI 等传统概念;
- HTTP/2 使用“HPACK”算法压缩头部信息,消除冗余数据节约带宽;
- HTTP/2 的消息不再是“Header+Body”的形式,而是分散为多个二进制“帧”;
- HTTP/2 使用虚拟的“流”传输消息,解决了困扰多年的“队头阻塞”问题,同时实现了“多路复用”,提高连接的利用率;
- HTTP/2 也增强了安全性,要求至少是 TLS1.2,而且禁用了很多不安全的密码套件。
时代之风(下):HTTP/2内核剖析(干货)
连接前言
TLS 握手成功之后,客户端必须要发送一个“连接前言”(connection preface),用来确认建立 HTTP/2 连接。
HTTP2的连接前言使用的是“Magic”确保使用的HTTP2
头部压缩 :smiling_imp:
头部压缩算法使用的是HPACK算法。它是一个“有状态”的算法,需要客户端和服务器各自维护一份“索引表”,也可以说是“字典”(这有点类似 brotli),压缩和解压缩就是查表和更新表的操作。 具体的实现为将原先头部的字段改为伪头部形式为“:authority”,":method"等来跟原先头部进行区分。HTTP/2 就为一些最常用的头字段定义了一个只读的“静态表”(Static Table)。通过key——value的形式如 ":method":2来表示GET请求,在发送时候只要一个字节发送对应的索引2就可以。
同时为了解决自定义字段找不到的问题,使用了动态表,跟在静态表的后面,在编码解码的时候随时更新。
二进制帧
格式
二进制帧头部占9个字节。 帧长度3个字节表示最大传输的大小为2^24 为16M,一般默认上限为2^14 为16Kb 帧类型,大致可以分成数据帧和控制帧两类,HEADERS 帧和 DATA 帧属于数据帧,存放的是 HTTP 报文,而 SETTINGS、PING、PRIORITY 等则是用来管理流的控制帧。
标志位:可以保存 8 个标志,携带简单的控制信息。常用的标志位有END_HEADERS表示头数据结束,相当于 HTTP/1 里头后的空行(“\r\n”),END_STREAM表示单方向数据发送结束(即 EOS,End of Stream),相当于 HTTP/1 里 Chunked 分块结束标志(“0\r\n\r\n”)。
流标识符:是用来确保多个复用的一个重要标志,接收方使用它就可以从乱序的帧里识别出具有相同流 ID 的帧序列,按顺序组装起来就实现了虚拟的“流”。拥有32位,最多可以表示21亿个标志,不过一般发送端使用的单数,服务端使用双数。单边流标志在10亿个左右。
流与多路复用
流是二进制帧的双向传输序列 **在 HTTP/2 连接上,虽然帧是乱序收发的,但只要它们都拥有相同的流 ID,就都属于一个流,而且在这个流里帧不是无序的,而是有着严格的先后顺序。**http2解决了原先请求响应的队头阻塞问题,需要明白的是并没有解决流内部的队头阻塞问题,因为HTTP2使用的仍是TCP协议,HTTP3改变使用UDP。
流的特点:
- 流是可并发的,一个 HTTP/2 连接上可以同时发出多个流传输数据,也就是并发多请求,实现“多路复用”;
- 客户端和服务器都可以创建流,双方互不干扰;
- 流是双向的,一个流里面客户端和服务器都可以发送或接收数据帧,也就是一个“请求 - 应答”来回;
- 流之间没有固定关系,彼此独立,但流内部的帧是有严格顺序的;
- 流可以设置优先级,让服务器优先处理,比如先传 HTML/CSS,后传图片,优化用户体验;
- 流 ID 不能重用,只能顺序递增,客户端发起的 ID 是奇数,服务器端发起的 ID 是偶数;
- 在流上发送“RST_STREAM”帧可以随时终止流,取消接收或发送;
- 第 0 号流比较特殊,不能关闭,也不能发送数据帧,只能发送控制帧,用于流量控制。
流状态转换
状态转换类似tcp的状态转换
总结:
- HTTP/2 必须先发送一个“连接前言”字符串,然后才能建立正式连接;
- HTTP/2 废除了起始行,统一使用头字段,在两端维护字段“Key-Value”的索引表,使用“HPACK”算法压缩头部;
- HTTP/2 把报文切分为多种类型的二进制帧,报头里最重要的字段是流标识符,标记帧属于哪个流;
- 流是 HTTP/2 虚拟的概念,是帧的双向传输序列,相当于 HTTP/1 里的一次“请求 - 应答”;
- 在一个 HTTP/2 连接上可以并发多个流,也就是多个“请求 - 响应”报文,这就是“多路复用”。
总结篇 探索篇 安全篇的部分内容没有记录 自己感觉在实践中没有太多用到,或者是自身储备不足。下次再做记录。