极客时间专栏:透视HTTP

01 | 时势与英雄:HTTP的前世今生

  • 目前全球有16亿个网站、2亿多个域名
  • 超文本标记语言,超文本传输协议
  • 0.9版本只包含GET获取HTML
  • 1995年发明Apache、1992年发明JPEG、1995年发明MP3音乐格式
  • 1.0增加了HEAD、POST等方法、增加了响应状态码标记了错误的原因、引入了协议版本号概念、引入了HTTP Header,让HTTP处理请求更加灵活、传输的数据不再仅限于文本
  • HTTP1.1增加了PUT\DELETE等新方法、增加了缓存管理、允许持久链接、允许数据分块利于大文件传输、强制要求让互联网主机托管成为可能
  • HTTP1.1让互联网呈现爆发式增长,但是互联网发展迅猛,HTTP1.1佁然不动,无奈只好用js等一些手段解决问题
  • Google推进HTTP2
  • HTTP2是二进制协议,不再是文本,可发起多个请求废弃了1.1里的管道,使用专用算法压缩头部减少数据传输量、允许服务器主动向客户端推送数据
  • HTTP3,也是google推出的QUIC协议,http3的阶段

02 | HTTP是什么?HTTP又不是什么?

  • HyperText Transfer Protocol

在这里插入图片描述

  • 两个以上参与就得出现协议、对参与者的行为的规范
  • 协议:通信的规范
  • 传输:双向协议、传输的过程中可以添加中间人,可以增加安全认证、数据压缩、编码转换等
  • HTTP不是孤立存在的,通常跑在TCP/IP协议栈之上,依靠IP协议实现寻址和路由、TCP协议实现可靠的数据传输、DNS协议实现域名的查找,还有一些协议依赖于HTTP如:WebSocket、HTTPDNS
  • HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。

03 | HTTP世界全览(上):与HTTP相关的各种概念

  • 我们通常所说的“上网”实际上访问的只是互联网的一个子集“万维网”(World Wide Web),它基于 HTTP 协议,传输 HTML 等超文本资源,能力也就被限制在 HTTP 协议之内。
  • 互联网上还有许多万维网之外的资源,例如常用的电子邮件、BT 和 Magnet 点对点下载、FTP 文件下载、SSH 安全登录、各种即时通信服务等等,它们需要用各自的专有协议来访问。
  • 不过由于 HTTP 协议非常灵活、易于扩展,而且“超文本”的表述能力很强,所以很多其他原本不属于 HTTP 的资源也可以“包装”成 HTTP 来访问,这就是我们为什么能够总看到各种“网页应用”——例如“微信网页版”“邮箱网页版”——的原因。
  • 综合起来看,现在的互联网 90% 以上的部分都被万维网,也就是 HTTP 所覆盖,所以把互联网约等于万维网或 HTTP 应该也不算大错。
  • CDN:内容分发网络、利用了HTTP的缓存和代理技术
  • CDN还提供负载均衡、安全防护、边缘计算等功能
  • 互联网至少有50%以上都是爬虫
  • web service:是一种由 W3C 定义的应用服务开发规范,使用 client-server 主从架构,通常使用 WSDL 定义服务接口,使用 HTTP 协议传输 XML 或 SOAP 消息,也就是说,它是一个基于 Web(HTTP)的服务架构技术,既可以运行在内网,也可以在适当保护后运行在外网。
  • WAF是近几年比较“火”的一个词,意思是“网络应用防火墙”。与硬件“防火墙”类似,它是应用层面的“防火墙”,专门检测 HTTP 流量,是防护 Web 应用的安全技术。
  • WAF 通常位于 Web 服务器之前,可以阻止如 SQL 注入、跨站脚本等攻击,目前应用较多的一个开源项目是 ModSecurity,它能够完全集成进 Apache 或 Nginx。

04 | HTTP世界全览(下):与HTTP相关的各种协议

在这里插入图片描述

  • IP 协议是“Internet Protocol”的缩写,主要目的是解决寻址和路由问题,以及如何在两点间传送数据包。
  • TCP 协议是“Transmission Control Protocol”的缩写,意思是“传输控制协议”,它位于 IP 协议之上,基于 IP 协议提供可靠的、字节流形式的通信,是 HTTP 协议得以实现的基础。
  • 在DNS中域名又称为主机名
  • 目前全世界有 13 组根 DNS 服务器,下面再有许多的顶级 DNS、权威 DNS 和更小的本地 DNS,逐层递归地实现域名查询。
  • HTTPS 它的全称是“HTTP over SSL/TLS”,也就是运行在 SSL/TLS 协议上的 HTTP。
  • 这里是 SSL/TLS,而不是 TCP/IP,它是一个负责加密通信的安全协议,建立在 TCP/IP 之上,所以也是个可靠的传输协议,可以被用作 HTTP 的下层。
  • HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”
  • SSL 的全称是“Secure Socket Layer”,由网景公司发明,当发展到 3.0 时被标准化,改名为 TLS,即“Transport Layer Security”,但由于历史的原因还是有很多人称之为 SSL/TLS,或者直接简称为 SSL。
  • SSL 使用了许多密码学最先进的研究成果,综合了对称加密、非对称加密、摘要算法、数字签名、数字证书等技术,能够在不安全的环境中为通信的双方创建出一个秘密的、安全的传输通道,为 HTTP 套上一副坚固的盔甲。
  • CDN

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


05 | 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?

  • 在工作中你一定经常听别人谈起什么“四层负载均衡”“七层负载均衡”,什么“二层转发”“三层路由”,那么你真正理解这些层次的含义吗?

  • TCP是字节流、UDP是分散的小数据包,是顺序发、乱序收

  • Mac层传输的单位是帧,IP层传输单位是包,TCO传输的单位是段,HTTP传输的单位是报文,统称为数据包
    在这里插入图片描述
    第一层:物理层,TCP/IP 里无对应;
    第二层:数据链路层,对应 TCP/IP 的链接层;
    第三层:网络层,对应 TCP/IP 的网际层;
    第四层:传输层,对应 TCP/IP 的传输层;
    第五、六、七层:统一对应到 TCP/IP 的应用层。

  • 所谓的“四层负载均衡”就是指工作在传输层上,基于 TCP/IP 协议的特性,例如 IP 地址、端口号等实现对后端服务器的负载均衡。

  • 所谓的“七层负载均衡”就是指工作在应用层上,看到的是 HTTP 协议,解析 HTTP 报文里的 URI、主机名、资源类型等数据,再用适当的策略转发给后端服务器。

  • 就是发快递的模型

  • 假设你想把一件毛绒玩具送给朋友,但你要先拿个塑料袋套一下,这件玩具就相当于 HTTP 协议里要传输的内容,比如 HTML,然后 HTTP 协议为它加一个 HTTP 专用附加数据。

你把玩具交给快递小哥,为了保护货物,他又加了层包装再贴了个标签,相当于在 TCP 层给数据再次打包,加上了 TCP 头。

接着快递小哥下楼,把包裹放进了三轮车里,运到集散点,然后再装进更大的卡车里,相当于在 IP 层、MAC 层对 TCP 数据包加上了 IP 头、MAC 头。

之后经过漫长的运输,包裹到达目的地,要卸货再放进另一位快递员的三轮车,就是在 IP 层、MAC 层传输后拆包。

快递员到了你朋友的家门口,撕掉标签,去除了 TCP 层的头,你朋友再拆掉塑料袋包装,也就是 HTTP 头,最后就拿到了玩具,也就是真正的 HTML 页面。

  • 但下层的传输过程对于上层是完全“透明”的,上层也不需要关心下层的具体实现细节,所以就 HTTP 层次来看,它不管下层是不是 TCP/IP 协议,看到的只是一个可靠的传输链路,只要把数据加上自己的头,对方就能原样收到。
  • OSI 分为七层,基本对应 TCP/IP,TCP 在第四层,HTTP 在第七层;
  • 有一个辨别四层和七层比较好的(但不是绝对的)小窍门,“两个凡是”:凡是由操作系统负责处理的就是四层或四层以下,否则,凡是需要由应用程序(也就是你自己写代码)负责处理的就是七层。

1 二层转发:设备工作在链路层,帧在经过交换机设备时,检查帧的头部信息,拿到目标mac地址,进行本地转发和广播
2 三层路由:设备工作在ip层,报文经过有路由功能的设备时,设备分析报文中的头部信息,拿到ip地址,根据网段范围,进行本地转发或选择下一个网关
3 DNS和CDN都在应用层


06 | 域名里有哪些门道?

  • DNS 的核心系统是一个三层的树状、分布式服务,基本对应域名的结构:
  • 根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等顶级域名服务器的 IP 地址;
  • 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址;
  • 权威域名服务器(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 查询的代理,代替用户访问核心 DNS 系统。这些“野生”服务器被称为“非权威域名服务器”,可以缓存之前的查询结果,如果已经有了记录,就无需再向根服务器发起查询,直接返回对应的 IP 地址。
  • 这些 DNS 服务器的数量要比核心系统的服务器多很多,而且大多部署在离用户很近的地方。比较知名的 DNS 有 Google 的“8.8.8.8”,Microsoft 的“4.2.2.1”,还有 CloudFlare 的“1.1.1.1”等等。
  • 其次,操作系统里也会对 DNS 解析结果做缓存,如果你之前访问过“www.apple.com”,那么下一次在浏览器里再输入这个网址的时候就不会再跑到 DNS 那里去问了,直接在操作系统里就可以拿到 IP 地址。
  • 另外,操作系统里还有一个特殊的“主机映射”文件,通常是一个可编辑的文本,在 Linux 里是“/etc/hosts”,在 Windows 里是“C:\WINDOWS\system32\drivers\etc\hosts”,如果操作系统在缓存里找不到 DNS 记录,就会找这个文件。
  • 有了上面的“野生”DNS 服务器、操作系统缓存和 hosts 文件后,很多域名解析的工作就都不用“跋山涉水”了,直接在本地或本机就能解决,不仅方便了用户,也减轻了各级 DNS 服务器的压力,效率就大大提升了。
  • 在 Nginx 里有这么一条配置指令“resolver”,它就是用来配置 DNS 服务器的,如果没有它,那么 Nginx 就无法查询域名对应的 IP,也就无法反向代理到外部的网站。
resolver 8.8.8.8 valid=30s;  # 指定 Google 的 DNS,缓存 30 秒
  • 因为有了域名,有了可以稳定工作的系统解析,于是可以实现比IP更多的新玩法
  • 第一种:重定向,因为域名代替了IP,所以可以让对外服务的域名不变而主机的IP任意变动,当有主机有情况需要下线的时候可以修改DNS记录,让域名指向其他机器,这样就可以保证业务服务不中断。
  • 因为域名是一个名字空间,所以可以使用 bind9 等开源软件搭建一个在内部使用的 DNS,作为名字服务器。这样我们开发的各种内部服务就都用域名来标记,比如数据库服务都用域名“mysql.inner.app”,商品服务都用“goods.inner.app”,发起网络通信时也就不必再使用写死的 IP 地址了,可以直接用域名,而且这种方式也兼具了第一种“玩法”的优势。
  • 也可以基于域名实现负载均衡,第一种方式,因为域名解析可以返回多个 IP 地址,所以一个域名可以对应多台主机,客户端收到多个 IP 地址后,就可以自己使用轮询算法依次向服务器发起请求,实现负载均衡。第二种方式,域名解析可以配置内部的策略,返回离客户端最近的主机,或者返回当前服务质量最好的主机,这样在 DNS 端把请求分发到不同的服务器,实现负载均衡。
  • DNS 就像是我们现实世界里的电话本、查号台,统管着互联网世界里的所有网站,是一个“超级大管家”;
  • DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存;
  • 使用 DNS 可以实现基于域名的负载均衡,既可以在内网,也可以在外网。

07 | 自己动手,搭建HTTP实验环境

  • 在浏览器和服务器之间还有一些“中间人”的角色,如 CDN、网关、代理等,它们也同样遵守 HTTP 协议,可以帮助用户更快速、更安全地获取资源。
  • 对 HTTP 更准确的称呼是“HTTP over TCP/IP”,而另一个“HTTP over SSL/TLS”就是增加了安全功能的 HTTPS。
C:\WINDOWS\system32\drivers\etc
  • windows下也存在一个文件的地址映射
    在这里插入图片描述

08 | 键入网址再按下回车,后面究竟发生了什么?

  • 在域名解析有多级缓存,浏览器先查看一些缓存,如果没有就向操作系统要,还没有就检查本机域名解析文件hosts,还有DNS缓存,CDN缓存服务端缓存。
  • 开始DNS解析,本地 DNS、根 DNS、顶级 DNS、权威 DNS 的层层解析,当然这中间有缓存,可能不会费太多时间就能拿到结果。
  • CDN会在 DNS 的解析过程中“插上一脚”。DNS 解析可能会给出 CDN 服务器的 IP 地址,这样你拿到的就会是 CDN 服务器而不是目标网站的实际地址。
  • 因为 CDN 会缓存网站的大部分资源,比如图片、CSS 样式表,所以有的 HTTP 请求就不需要再发到 Apple,CDN 就可以直接响应你的请求,把数据发给你。
  • 由 PHP、Java 等后台服务动态生成的页面属于“动态资源”,CDN 无法缓存,只能从目标网站获取。于是你发出的 HTTP 请求就要开始在互联网上的“漫长跋涉”,经过无数的路由器、网关、代理,最后到达目的地。
  • 目标网站的服务器对外表现的是一个 IP 地址,但为了能够扛住高并发,在内部也是一套复杂的架构。通常在入口是负载均衡设备,例如四层的 LVS 或者七层的 Nginx,在后面是许多的服务器,构成一个更强更稳定的集群。
  • 负载均衡设备会先访问系统里的缓存服务器,通常有 memory 级缓存 Redis 和 disk 级缓存 Varnish,它们的作用与 CDN 类似,不过是工作在内部网络里,把最频繁访问的数据缓存几秒钟或几分钟,减轻后端应用服务器的压力。
  • 如果缓存服务器里也没有,那么负载均衡设备就要把请求转发给应用服务器了。这里就是各种开发框架大显神通的地方了,例如 Java 的 Tomcat/Netty/Jetty,Python 的 Django,还有 PHP、Node.js、Golang 等等。它们又会再访问后面的 MySQL、PostgreSQL、MongoDB 等数据库服务,实现用户登录、商品查询、购物下单、扣款支付等业务操作,然后把执行的结果返回给负载均衡设备,同时也可能给缓存服务器里也放一份。
  • 应用服务器的输出到了负载均衡设备这里,请求的处理就算是完成了,就要按照原路再走回去,还是要经过许多的路由器、网关、代理。如果这个资源允许缓存,那么经过 CDN 的时候它也会做缓存,这样下次同样的请求就不会到达源站了。
  • 最后网站的响应数据回到了你的设备,它可能是 HTML、JSON、图片或者其他格式的数据,需要由浏览器解析处理才能显示出来,如果数据里面还有超链接,指向别的资源,那么就又要重走一遍整个流程,直到所有的资源都下载完。

09 | HTTP报文是什么样子的?

  • TCP报文附加了20个字节的头部数据,存储TCP协议必须的额外的信息,发送端口号、接受方的端口号、包序号、标志位等
  • 有了这个附加的 TCP 头,数据包才能够正确传输,到了目的地后把头部去掉,就可以拿到真正的数据。

在这里插入图片描述

  • HTTP 协议也是与 TCP/UDP 类似,同样也需要在实际传输的数据前附加一些头数据,不过与 TCP/UDP 不同的是,它是一个“纯文本”的协议,所以头数据都是 ASCII 码的文本,可以很容易地用肉眼阅读,不用借助程序解析也能够看懂。
  • HTTP 协议规定报文必须有 header,但可以没有 body,而且在 header 之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”。

在这里插入图片描述

在这里插入图片描述

  • 在很多时候,特别是浏览器发送 GET 请求的时候都是这样,HTTP 报文经常是只有 header 而没 body
  • 虽然 HTTP 协议对 header 的大小没有做限制,但各个 Web 服务器都不允许过大的请求头,因为头部太大可能会占用大量的服务器资源,影响运行效率。
GET / HTTP/1.1

在这个请求行里,“GET”是请求方法,“/”是请求目标,“HTTP/1.1”是版本号,把这三部分连起来,意思就是“服务器你好,我想获取网站根目录下的默认文件,我用的协议版本号是 1.1,请不要用 1.0 或者 2.0 回复我。”

在这里插入图片描述

在这里插入图片描述

  1. 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
  2. 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;
  3. 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;
  4. 字段的顺序是没有意义的,可以任意排列不影响语义;
  5. 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。
  • 400:请求报文格式有误
  • host字段告诉服务器这个请求那个主机来处理,当一台计算机上托管了多个虚拟主机的时候,服务端就要用Host字段来选择,有点像简单的路由重定向
  • 用host来区分ip相同但是域名不同的网站,否则服务器就会找不到合适的虚拟主机
  • 响应头的server字段最好不要暴露信息
  • 实体字段还有一个content-length表示报文里body的长度,也就是请求头或响应头空行后面数据的长度,服务器看到这个字段,就知道后续有多少数据了,可以直接接受,如果没有这个字段,那么body就是不定长的,需要chunked方式分段传输
  • 请求头由“请求行 + 头部字段”构成,响应头由“状态行 + 头部字段”构成;
  • 头部字段是 key-value 的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;
  • HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。

10 | 应该如何理解请求方法?

  • DELETE方法指示服务器删除资源,因为这个动作危险性太大,所以通常服务器不会执行真正的删除操作,而是对资源做一个删除标记。当然,更多的时候服务器就直接不处理 DELETE 请求。
  • CONNECT是一个比较特殊的方法,要求服务器为客户端和另一台远程服务器建立一条特殊的连接隧道,这时 Web 服务器在中间充当了代理的角色。
  • TRACE方法多用于对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径。它的本意是好的,但存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用。
  • 此外,还有一些得到了实际应用的请求方法(WebDAV),例如 MKCOL、COPY、MOVE、LOCK、UNLOCK、PATCH 等。如果有合适的场景,你也可以把它们应用到自己的系统里,比如用 LOCK 方法锁定资源暂时不允许修改,或者使用 PATCH 方法给资源打个小补丁,部分更新数据。但因为这些方法是非标准的,所以需要为客户端和服务器编写额外的代码才能添加支持。
  • 当然了,你也完全可以根据实际需求,自己发明新的方法,比如“PULL”拉取某些资源到本地,“PURGE”清理某个目录下的所有缓存数据。
  • 安全和幂等:
  • 在 HTTP 协议里,所谓的“安全”是指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。
  • 按照这个定义,只有 GET 和 HEAD 方法是“安全”的,因为它们是“只读”操作,只要服务器不故意曲解请求方法的处理方式,无论 GET 和 HEAD 操作多少次,服务器上的数据都是“安全的”。
  • 而 POST/PUT/DELETE 操作会修改服务器上的资源,增加或删除数据,所以是“不安全”的。
  • 所谓的“幂等”实际上是一个数学用语,被借用到了 HTTP 协议里,意思是多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”。
  • 很显然,GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的。
  • 按照 RFC 里的语义,POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT 是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的。
  • 对比SQL来加深理解,Post理解为insert,put理解为update,多次insert会添加多条记录,多次update只操作一条记录,效果相同
  • HEAD 方法是轻量级的 GET,用来获取资源的元信息;

11 | 你能写出正确的网址吗?

  • 在测试、运维配置 Apache、Nginx 等 Web 服务器的时候也必须正确理解 URI,分离静态资源与动态资源,或者设置规则实现网页的重定向跳转。
  • scheme:协议名
  • 客户端和服务器看到的 URI 是不一样的。客户端看到的必须是完整的 URI,使用特定的协议去连接特定的主机,而服务器看到的只是报文请求行里被删除了协议名和主机名的 URI。
  • 如果你配置过 Nginx,你就应该明白了,Nginx 作为一个 Web 服务器,它的 location、rewrite 等指令操作的 URI 其实指的是真正 URI 里的 path 和后续的部分。
  • URI 引入了编码机制,对于 ASCII 码以外的字符集和特殊字符做一个特殊的操作,把它们转换成与 URI 语义不冲突的形式。这在 RFC 规范里称为“escape”和“unescape”,俗称“转义”。
  • URI 转义的规则有点“简单粗暴”,直接把非 ASCII 码或特殊字符转换成十六进制字节值,然后前面再加上一个“%”。
  • 例如,空格被转义成“%20”,“?”被转义成“%3F”。而中文、日文等则通常使用 UTF-8 编码后再转义,例如“银河”会被转义成“%E9%93%B6%E6%B2%B3”。
  • 不过我们在浏览器的地址栏里通常是不会看到这些转义后的“乱码”的,这实际上是浏览器一种“友好”表现,隐藏了 URI 编码后的“丑陋一面”,不信你可以试试下面的这个 URI。
http://www.chrono.com:8080/11-1? 夸父逐日
  • 先在 Chrome 的地址栏里输入这个 query 里含有中文的 URI,然后点击地址栏,把它再拷贝到其他的编辑器里,它就会“现出原形”:
http://www.chrono.com:8080/11-1?%E5%A4%B8%E7%88%B6%E9%80%90%E6%97%A5

13 | HTTP有哪些特点?

  • HTTP有链接无状态
  • HTTP灵活可扩展,可以添加头字段
  • 如果要保证收发数据100%可用就不能用HTTP需要消息中间件,RabbitMQ、ZeroMQ、Kafka等
  • 之间HTTP有无连接的特点,指的是协议不保持链接状态,每次请求应答后都会关闭,但是在HTTP1.1里改成keepalive长链接机制,所以现在的HTTP不再是无连接
  • 灵活可扩张是最大优点吧。可靠性比不上MQ,
    传输数据虽然通用,可是文件传输时效率肯定比不是FTP
  • 无状态,在需要状态的地方通过扩展弥补不足。
    请求应答,有些需要服务器主动推得需要用websocket协议。

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

  • HTTPS和HTTP2都是基于HTTP1.1的完善
  • 所谓“少即是多”,“把简单的系统变复杂”,要比“把复杂的系统变简单”容易得多。
  • 灵活和易于扩展
  • 基于UDP的QUIC
  • web性能优化,有了很好的解决方案:HTTP2/3
  • 而“请求 - 应答”模式则加剧了 HTTP 的性能问题,这就是著名的“队头阻塞”(Head-of-line blocking),当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。
  • HTTP是无状态的可以轻松实现集群化、扩展性能,但有时也需要cookie技术来实现有状态

15 | 海纳百川:HTTP的实体数据

  • MIME 是一个很大的标准规范,但 HTTP 只“顺手牵羊”取了其中的一部分,用来标记 body 的数据类型,这就是我们平常总能听到的“MIME type”。
  • 在 HTTP 里经常遇到的几个类别:

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,即不透明的二进制数据。

  • 只有MIME type还不够,因为在传输时为了节约带宽还会压缩数据,为了不让浏览器去试还会有一个 ENcoding type告诉用的是什么编码格式,才可以正确的解压
  • gzip:也是互联网最流行的压缩格式,br一种专门为HTTP优化的新压缩算法
  • accept字段可以理解为告诉服务器我能看懂什么HTML,XML等
  • 服务器会在响应报文里用头字段Content-Type告诉实体的数据类型
Content-Type: text/html
Content-Type: image/png
Accept-Encoding: gzip, deflate, br
Content-Encoding: gzip
  • 后面两个字段是可以省略的,如果没有Accept-Encoding就是不支持数据压缩,如果响应没有Content-Encoding就表示响应数据没有被压缩
  • HTTP还引入了国际化的解决方案
  • 在计算机发展的早期,各个国家和地区的人们“各自为政”,发明了许多字符编码方式来处理文字,比如英语世界用的 ASCII、汉语世界用的 GBK、BIG5,日语世界用的 Shift_JIS 等。同样的一段文字,用一种编码显示正常,换另一种编码后可能就会变得一团糟。
  • 所以后来就出现了 Unicode 和 UTF-8,把世界上所有的语言都容纳在一种编码方案里,UTF-8 也成为了互联网上的标准字符集。
  • Accept-Language字段标记了客户端可理解的自然语言,也允许用“,”做分隔符列出多个类型,例如:
Accept-Language: zh-CN, zh, en
  • 相应的,服务器应该在响应报文里用头字段Content-Language告诉客户端实体数据使用的实际语言类型:
Content-Language: zh-CN
  • 字符集在 HTTP 里使用的请求头字段是Accept-Charset,但响应头里却没有对应的 Content-Charset,而是在Content-Type字段的数据类型后面用“charset=xxx”来表示,这点需要特别注意。

  • 不过现在的浏览器都支持多种字符集,通常不会发送 Accept-Charset,而服务器也不会发送 Content-Language,因为使用的语言完全可以由字符集推断出来,所以在请求头里一般只会有 Accept-Language 字段,响应头里只会有 Content-Type 字段。

在这里插入图片描述

  • 在HTTP中;的权重是小于,的
  • vary字段是响应报文的特殊标记

在这里插入图片描述

  • accept-type表示想接受的,content-type代表你发送的

16 | 把大象装进冰箱:HTTP传输大文件的方法

  • 如何在有限的带宽高效的传输大文件
  • 可以进行压缩
  • gzip只对文本有效,对于多媒体视频本身就是高度压缩了,再用gzip处理也不会变小
  • 在nginx中就是使用gzip on指令对text/html进行压缩
  • 将文件拆开,分块发给浏览器,浏览器再收到后组装复原,在HTTP里就是chunked来表示不是一次性发过来的分成了多块,逐个发送
  • 分块传输也可以用于流式数据,由于数据库动态生成表单页面,在这种情况下,body数据长度是未知的,无法在头字段content-length里确切给出答案,只能用chunked方式分块发送

17 | 排队也要讲效率:HTTP的连接管理

  • TCP的链接需要7次数据包,HTTP只需要4次
  • 长链接也是提高效率的方式
  • 在HTTP里默认使用长链接
  • 使用的字段是Connection,值是“keep-alive”
  • 不过不管客户端是否显式要求长连接,如果服务器支持长连接,它总会在响应报文里放一个“Connection: keep-alive”字段,告诉客户端:“我是支持长连接的,接下来就用这个 TCP 一直收发数据吧”
  • 长链接有缺点:消耗内存资源
  • 在客户端,可以在请求头里加上“Connection: close”字段,告诉服务器:“这次通信后就关闭连接”。服务器看到这个字段,就知道客户端要主动关闭连接,于是在响应报文里也加上这个字段,发送之后就调用 Socket API 关闭 TCP 连接。
  • 服务器端一般不会主动关闭连接,但是也有一些策略,比如nginx

使用“keepalive_timeout”指令,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发就主动断开连接,避免空闲连接占用系统资源。
使用“keepalive_requests”指令,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,也会主动断开连接。

  • 客户端和服务器都可以在报文里附加通用头字段“Keep-Alive: timeout=value”,限定长连接的超时时间。但这个字段的约束力并不强,通信的双方可能并不会遵守,所以不太常见。
  • 实验环境配置了“keepalive_timeout 60”和“keepalive_requests 5”,意思是空闲连接最多 60 秒,最多发送 5 个请求。所以,如果连续刷新五次页面,就能看到响应头里的“Connection: close”了。
  • 队头阻塞:因为HTTO报文必须是一发一收,就形成了先进先出的穿行队列
  • 队列不是优先队列,当队首请求太慢耽误了时间后面只能等着
  • 队头阻塞的问题在HTTP1.1里无法解决,只能缓解:
  • 解决方法:可以使用并发连接,对一个域名发起多个长链接,用数量解决质量的问题,但是太过于消耗资源,每个客户端最多并发2个链接,但是众多浏览器上限提高到6-8
  • 还可以域名分片的技术,一个服务器对应多个域名,这样实际长链接的数量就上去了
  • TCP协议有慢启动,阻塞窗口等特性,所以冷链接会比较慢
  • 长链接最好使用content-lenght明确响应实体的长度,正确标记报文结束。如果是流式传输,必须用分块传输编码
  • 利用HTTP请求的长链接特性对服务器发起大量的请求导致服务器最终资源耗尽拒绝服务就是常说的DDos
  • HTTP的链接管理还有第三种方式,叫pipline,在长链接的基础上又进了一步,可以批量单额接受相应,但是存在一些问题被chrome等废弃了
  • connetion字段还有一个值:connection:upgrade,配合状态码101表示协议升级,从HTTP----Websocket
  • http是半双工:只能一来一回,这就是队头阻塞的根源
  • 思考:在开发基于HTTP协议的客户端服务器时应该使用何种链接模式
  • 如何降低长链接对服务器的负面影响

一般使用长连接,除非明确知道只会发送一个请求,比如游戏内连接兑换码服务进行礼包兑换。
1,服务器端设置keepalive_timeout表示多长时间没有数据则关闭连接。
2,服务器端设置keepalive_requests,表示该连接上处理多少个请求后关闭连接。
3,服务器端设置最大连接数,当连接达到上限之后拒绝连接,也可以采用限流措施等。


18 | 四通八达:HTTP的重定向和跳转

  • location:重定向的体现
  • 如果有location就会默认跳转,代替人类进行点击,默认发送请求
http://www.chrono.com/18-1?dst=nginx.org           # 错误
http://www.chrono.com/18-1?dst=http://nginx.org    # 正确
  • 301:永久重定向
  • 302:临时重定向
  • 可以做一个类似的负载均衡
  • 服务降级也可能会用到重定向
  • 重定向应该适度使用,不能滥用
  • 循环跳转浏览器应该报错
  • 重定向是服务端发起的跳转,用户无感知
  • 要当心性能损耗和循环跳转

19 | 让我知道你是谁:HTTP的Cookie机制

  • 相当于服务器给客户端发送小纸条
  • 响应头:set-cookie 请求头:cookie
  • 服务器可能添加多个set-cookie
  • cookie只有对浏览器生效
  • cookie就是服务器委托浏览器存的一些信息,因为服务器记不住啊
  • 应该设置cookie的生命周期
  • “Expires”俗称“过期时间”,用的是绝对时间点,可以理解为“截止日期”(deadline)。
  • “Max-Age”用的是相对时间,单位是秒,浏览器用收到报文的时间点再加上 Max-Age,就可以得到失效的绝对时间。
  • 设置cookie的作用域,“Domain”和“Path”指定了 Cookie 所属的域名和路径,浏览器在发送 Cookie 前会从 URI 中提取出 host 和 path 部分,对比 Cookie 的属性。如果不满足条件,就不会在请求头里发送 Cookie。
  • 可以为不同的域名和路径设置cookie
  • httponly会告诉浏览器此cookie只能通过浏览器http协议传输,禁止其他方式访问,浏览器js引擎就会禁用document.cookie等相关的api
  • csrf防止跨站攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。
  • Chrome 开发者工具是查看 Cookie 的有力工具,在“Network-Cookies”里可以看到单个页面 Cookie 的各种属性,另一个“Application”面板里则能够方便地看到全站的所有 Cookie。
  • cookie还有一个用途就是广告跟踪,上网时有很多广告,图片的背后都是广告商网站,会偷偷给你贴上cookie,这样在上其他网站的时候别的广告就能用cookie读出你的身份然后做出行为分析,再推给你广告。又称为第三方cookie

总结:

  • cookie是服务器委托浏览器存储的一些数据,让服务器有了记忆能力
  • 为了保护cookie还要给其设置有效期,作用域等属性,常用的有max-age、expires、domain、httponly等
  • 如果max-age值小于等于0则立即过期

20 | 生鲜速递:HTTP的缓存控制

  • 缓存:优化系统性能的利器
  • http的每个环节几乎都会有缓存

浏览器发现缓存无数据,于是发送请求,向服务器获取资源;
服务器响应请求,返回资源,同时标记资源的有效期;
浏览器缓存资源,等待下次重用。

  • 服务器标记资源有效期使用的头字段是“Cache-Control”,里面的值“max-age=30”就是资源的有效时间,相当于告诉浏览器,“这个页面只能缓存 30 秒,之后就算是过期,不能用。
  • 缓存的有效期就好比保质期
  • no_store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;
  • no_cache:它的字面含义容易与 no_store 搞混,实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本;
  • must-revalidate:又是一个和 no_cache 相似的词,它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证。

no_store:买来的西瓜不允许放进冰箱,要么立刻吃,要么立刻扔掉;
no_cache:可以放进冰箱,但吃之前必须问超市有没有更新鲜的,有就吃超市里的;
must-revalidate:可以放进冰箱,保鲜期内可以吃,过期了就要问超市让不让吃。

  • 在http中服务器就是那么霸气

在这里插入图片描述

  • 浏览器也可以发送Cache-Control
  • 浏览器的前进后退按钮都使用了浏览器的缓存
  • 条件请求:我们最常用的是“if-Modified-Since”和“If-None-Match”这两个。需要第一次的响应报文预先提供“Last-modified”和“ETag”,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。
  • etag:实体标签

总结

  • 验证资源是否失效,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以复用缓存里的资源;
  • 验证资源是否被修改的条件有两个:“Last-modified”和“ETag”,需要服务器预先在响应报文里设置,搭配条件请求使用;
  • 浏览器也可以发送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新数据。
  • cache和cookie有什么区别:cookie会随着请求报文发送到服务器,cache不会但可能会携带 if-Modified-Since(保存资源的最后修改时间)和 If-None-Match(保存资源唯一标识) 字段来验证资源是否过期。
  • nginx和apache都会使用etag
  • etag是资源的唯一标签,主要用来解决修改时间无法准确区分文件变化的问题,etag有强弱之分

21 | 良心中间商:HTTP的代理服务

  • 负载均衡算法:轮询,一致性哈希
  • 限制ip或抵制流量,使用SSL通信加密,数据过滤,内容缓存
  • 为http增加了更多的灵活性
  • HTTP为明文传输,请求头容易被篡改,所以X-Forwarded-for也是不完全可信的
  • 代理会成为性能瓶颈,有单点问题

22 | 冷链周转:HTTP的缓存代理

  • 支持缓存控制的代理服务
  • 服务器的缓存也是很有价值的
  • 当代理服务器加入了缓存就可以直接返回

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


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

  • 因为HTTP是不安全的,因为明文传输
  • 任何人都可以截获,作为HTTP的中间人
  • HTTPS将下层的协议由TCP/IP换成了SSL/TLS
  • SSL安全套阶层,处于第五层
  • TLS:传输层安全,1.2版本最为流行
  • 客户端和服务端可以支持很多的套件,最后进行协商openSSL是开源的密码库很多应用软件都使用其作为底层库来实现TLS功能
  • 明文、不安全vs四个特性,端口80vs443,无加密解密流畅性vs一定的性能消耗,对称加密算法保证机密性,散列值算法保证完成性和安全性
  • 机密性由对称加密AES保证,完整性由SHA384摘要算法,身份认证和不可否认由RSA非对称加密保证

24 | 固若金汤的根本(上):对称加密与非对称加密

  • 对称加密加非对称加密组成了TLS
  • 私钥加密公钥进行解密用来做身份认证,不可抵赖,因为默认私钥只有持有人知道
  • 私钥加密可以用于数字签名、身份认证

25 | 固若金汤的根本(下):数字签名与证书

发布了140 篇原创文章 · 获赞 53 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291044/article/details/103367855