http前世今生
1989 年蒂姆·伯纳斯 - 李(Tim Berners-Lee)发表了一篇论文,提出了在互联网上构建超链接文档系统的构想。这篇论文中他确立了三项关键技术。
- URI:即统一资源标识符,作为互联网上资源的唯一身份。
- HTML:即超文本标记语言,描述超文本文档。
- HTTP:即超文本传输协议,用来传输超文本。
http / 0.9
为了便于服务器和客户端处理,它也采用了纯文本格式。 蒂姆·伯纳斯 - 李最初设想的系统里的文档都是只读的,所以只允许用“GET”动作从服务器上获取 HTML 文档,并且在响应请求之后立即关闭连接,功能非常有限。
- 第一个是只有一个请求行,并没有 HTTP 请求头和请求体,因为只需要一个请求行就可以完整表达客户端的需求了。
- 第二个是服务器也没有返回头信息,这是因为服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了。
- 第三个是返回的文件内容是以 ASCII 字符流来传输的,因为都是 HTML 格式的文件,所以使用 ASCII 字节码来传输是最合适的。
http / 1.0
1996 年正式发布。并加入了很多内容:
- 增加了 HEAD、POST 等新方法;
- 增加了响应状态码,标记可能的错误原因;
- 引入了协议版本号概念;
- 引入了 HTTP Header(头部)的概念,让 HTTP 处理请求和响应更加灵活;
- 传输的数据不再仅限于文本。 但 HTTP/1.0 并不是一个“标准”,只是记录已有实践和模式的一份参考文档,不具有实际的约束力,相当于一个“备忘录”。
http / 1.1
1999 年, http / 1.1正式发布。从版本号我们就可以看到,HTTP/1.1 是对 HTTP/1.0 的小幅度修正。但一个重要的区别是:它是一个“正式的标准”,而不是一份可有可无的“参考文档”。HTTP/1.1 主要的变更点有:
- 增加了 PUT、DELETE 等新的方法;
- 增加了缓存管理和控制;
- 明确了连接管理,允许持久连接;
- 就是由于长链接。导致队头阻塞问题。通过管线化的技术来解决队头阻塞的问题。HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。
- 允许响应数据分块(chunked),利于传输大文件;
- 强制要求 Host 头,让互联网主机托管成为可能。
- 增加cookie,来保存用户状态。
http / 2
根据google提出的SPDY 协议,指定新版本的http协议。在2015年发布。HTTP/2 的制定充分考虑了现今互联网的现状:宽带、移动、不安全,在高度兼容 HTTP/1.1 的同时在性能改善方面做了很大努力,主要的特点有:
- 二进制协议,不再是纯文本;
- 可发起多个请求,废弃了 1.1 里的管道;
- 多路复用(HTTP/2 的最核心功能),它能实现资源的并行传输。多路复用技术是建立在二进制分帧层的基础之上。
- 可以设置请求的优先级。
- 使用专用算法压缩头部,减少数据传输量;
- 允许服务器主动向客户端推送数据;
- 增强了安全性,“事实上”要求加密通信。
http / 3
根据google提出的QUIC协议。2018 年,互联网标准化组织 IETF 提议将“HTTP over QUIC”更名为“HTTP/3”。
http是什么
- TTP 就是超文本传输协议,也就是 HyperText Transfer Protocol。
- 协议的理解:HTTP 是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。
- 传输的理解:HTTP 协议是一个双向协议。HTTP 是一个在计算机世界里专门用来在两点之间(但是可以有中间人)传输数据的约定和规范。
- 超文本的理解:不是 TCP/UDP 这些底层协议里被切分的杂乱无章的二进制包(datagram),而是完整的、有意义的数据,可以被浏览器、服务器这样的上层应用程序处理。它是文字、图片、音频和视频等的混合体,最关键的是含有“超链接”,能够从一个“超文本”跳跃到另一个“超文本”,形成复杂的非线性、网状的结构关系。
- HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。 HTTP不是互联网、不是编程语言、不是HTML,不是一个孤立的协议。 HTTP通常跑在TCP/IP协议栈之上,依靠IP实现寻址和路由、TCP协议实现可靠数据传输、DNS协议实现域名查找、SSL/TLS协议实现安全通信。此外,还有一些协议依赖于HTTP,例如WebSocket、HTTPDNS等。这些协议相互交织,构成了一个协议网,而HTTP则处于中心地位。
http协议全览
万维网
互联网的正式名称是 Internet,里面存储着无穷无尽的信息资源,我们通常所说的“上网”实际上访问的只是互联网的一个子集“万维网”(World Wide Web),它基于 HTTP 协议,传输 HTML 等超文本资源,能力也就被限制在 HTTP 协议之内。 互联网上还有许多万维网之外的资源,例如常用的电子邮件、BT 和 Magnet 点对点下载、FTP 文件下载、SSH 安全登录、各种即时通信服务等等,它们需要用各自的专有协议来访问。
不过由于 HTTP 协议非常灵活、易于扩展,而且“超文本”的表述能力很强,所以很多其他原本不属于 HTTP 的资源也可以“包装”成 HTTP 来访问,这就是我们为什么能够总看到各种“网页应用”——例如“微信网页版”“邮箱网页版”——的原因。
CDN
CDN,全称是“Content Delivery Network”,翻译过来就是内容分发网络。它应用了 HTTP 协议里的缓存和代理技术,代替源站响应客户端的请求。它可以缓存源站的数据。
它就是专门为解决“长距离”上网络访问速度慢而诞生的一种网络应用服务。
CDN 的最核心原则是就近访问,如果用户能够在本地几十公里的距离之内获取到数据,那么时延就基本上变成 0 了。
cdn将原站上的数据缓存到每个网络节点上。用户在上网的时候就不直接访问源站,而是访问离他“最近的”一个 CDN 节点,术语叫“边缘节点”(edge node),其实就是缓存了源站内容的代理服务器,这样一来就省去了“长途跋涉”的时间成本,实现了“网络加速”。
CDN 的负载均衡
我们再来看看 CDN 是具体怎么运行的,它有两个关键组成部分:全局负载均衡和缓存系统。
全局负载均衡(Global Sever Load Balance)一般简称为 GSLB,它是 CDN 的“大脑”,主要的职责是当用户接入网络的时候在 CDN 专网中挑选出一个“最佳”节点提供服务,解决的是用户如何找到“最近的”边缘节点,对整个 CDN 网络进行“负载均衡”。
缓存系统是 CDN 的另一个关键组成部分,相当于 CDN 的“心脏”。如果缓存系统的服务能力不够,不能很好地满足用户的需求,那 GSLB 调度算法再优秀也没有用。缓存系统只能有选择地缓存那些最常用的那些资源。
TCP/IP协议
TCP/IP 协议实际上是一系列网络通信协议的统称,其中最核心的两个协议是 TCP 和 IP,其他的还有 UDP、ICMP、ARP 等等,共同构成了一个复杂但有层次的协议栈。
这个协议栈有四层,最上层是“应用层”,最下层是“链接层”,TCP 和 IP 则在中间:TCP 属于“传输层”,IP 属于“网际层”。
IP 协议是“Internet Protocol”的缩写,主要目的是解决寻址和路由问题,以及如何在两点间传送数据包。IP 协议使用“IP 地址”的概念来定位互联网上的每一台计算机。
TCP 协议是“Transmission Control Protocol”的缩写,意思是“传输控制协议”,它位于 IP 协议之上,基于 IP 协议提供可靠的、字节流形式的通信,是 HTTP 协议得以实现的基础。“可靠”是指保证数据不丢失,“字节流”是指保证数据完整。
DNS
在 TCP/IP 协议中使用 IP 地址来标识计算机,数字形式的地址对于计算机来说是方便了,但对于人类来说却既难以记忆又难以输入。于是“域名系统”(Domain Name System)出现了,用有意义的名字来作为 IP 地址的等价替代。
域名用“.”分隔成多个单词,级别从左到右逐级升高,最右边的被称为“顶级域名”。
但想要使用 TCP/IP 协议来通信仍然要使用 IP 地址,所以需要把域名做一个转换,“映射”到它的真实 IP,这就是所谓的“域名解析”。
URI/URL
DNS 和 IP 地址只是标记了互联网上的主机,但主机上有那么多文本、图片、页面,到底要找哪一个呢?这就需要URI (统一资源标识符) 表示互联网上的资源。
URI 另一个更常用的表现形式是 URL(Uniform Resource Locator),统一资源定位符,也就是我们俗称的“网址”,它实际上是 URI 的一个子集,不过因为这两者几乎是相同的,差异不大,所以通常不会做严格的区分。
HTTPS
在 TCP/IP、DNS 和 URI 的“加持”之下,HTTP 协议终于可以自由地穿梭在互联网世界里,顺利地访问任意的网页了,真的是“好生快活”。
由于http传输的内容明文,所以不安全。这就需要将数据加密后传输。HTTP over SSL/TLS,也就是运行在 SSL/TLS 协议上的 HTTP。它是一个负责加密通信的安全协议,建立在 TCP/IP 之上,所以也是个可靠的传输协议,可以被用作 HTTP 的下层。
因为 HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,其中的“HTTP”和“TCP/IP”我们都已经明白了,只要再了解一下 SSL/TLS,HTTPS 也就能够轻松掌握。
SSL 使用了许多密码学最先进的研究成果,综合了对称加密、非对称加密、摘要算法、数字签名、数字证书等技术,能够在不安全的环境中为通信的双方创建出一个秘密的、安全的传输通道,为 HTTP 套上一副坚固的盔甲。
代理
代理(Proxy)是 HTTP 协议中请求方和应答方中间的一个环节,作为“中转站”,既可以转发客户端的请求,也可以转发服务器的应答。
- 匿名代理:完全“隐匿”了被代理的机器,外界看到的只是代理服务器;
- 透明代理:顾名思义,它在传输过程中是“透明开放”的,外界既知道代理,也知道客户端;
- 正向代理:靠近客户端,代表客户端向服务器发送请求;
- 反向代理:靠近服务器端,代表服务器响应客户端的请求; CDN,实际上就是一种代理,它代替源站服务器响应客户端的请求,通常扮演着透明代理和反向代理的角色。
由于代理在传输过程中插入了一个“中间层”,所以可以在这个环节做很多有意思的事情,比如:
- 负载均衡:把访问请求均匀分散到多台机器,实现访问集群化;
- 内容缓存:暂存上下行的数据,减轻后端的压力;
- 安全防护:隐匿 IP, 使用 WAF 等工具抵御网络攻击,保护被代理的机器;
- 数据处理:提供压缩、加密等额外的功能。
http协议的特点
- 灵活可扩展。 随着不断地发展,http从最初的只支持get请求获取文本资源,到现在可以通过各种方法处理各种流媒体文件。
- 可靠传输。 因为 HTTP 协议是基于 TCP/IP 的,而 TCP 本身是一个“可靠”的传输协议。
- 应用层协议。 HTTP 凭借着可携带任意头字段和实体数据的报文结构,以及连接控制、缓存代理等方便易用的特性。 几乎可以传递一切东西,满足各种需求,称得上是一个“万能”的协议。
- 请求 - 应答。 客户端主动发起请求,服务器被动回复请求。
- 无状态。 但是在http / 1.1有了长连接机制,就不再是无连接的了。
TCP/IP协议族
TCP/IP协议其实是一系列与互联网关联的协议集合起来的总称。分层管理是TCP/IP协议的重要特征。 它分为四层,层次顺序从下往上。
- 第一层链路层。负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备,所以有时候也叫 MAC 层。
- 第二层 网际层 或者 网络互连层。IP 协议就处在这一层。用 IP 地址取代 MAC 地址,把许许多多的局域网、广域网连接成一个虚拟的巨大网络,在这个网络里找设备时只要把 IP 地址再“翻译”成 MAC 地址就可以了。
- 第三层传输层。这个层次协议的职责是保证数据在 IP 地址标记的两点之间“可靠”地传输,是 TCP 协议工作的层次,另外还有它的一个“小伙伴”UDP。
- TCP: 有状态的协议,需要先与对方建立连接然后才能发送数据,而且保证数据不丢失不重复。TCP 的数据是连续的“字节流”,有先后顺序
- UDP: 它无状态,不用事先建立连接就可以任意发送数据。UDP 则是分散的小数据包,是顺序发,乱序收。
- 第四层应用层。这一层有各种面向具体应用的协议。例如 Telnet、SSH、FTP、SMTP 等等,当然还有我们的 HTTP。 MAC 层的传输单位是帧(frame),IP 层的传输单位是包(packet),TCP 层的传输单位是段(segment),HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包。
数据包的封装过程
数据包传输过程
HTTP 协议的传输过程就是这样通过协议栈逐层向下,每一层都添加本层的专有数据,层层打包,然后通过下层发送出去。
接收数据则是相反的操作,从下往上穿过协议栈,逐层拆包,每层去掉本层的专有头,上层就会拿到自己的数据。
DNS解析
就像 IP 地址必须转换成 MAC 地址才能访问主机一样,域名也必须要转换成 IP 地址,这个过程就是“域名解析”。
DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存。
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 地址。 域名解析过程:
- dns解析域名是有层次的。采用就近原则。
- 本机会将我们经常访问的域名和响应的ip地址建立一个映射关系,并保存在本地host文件中。
- 先在浏览器缓存中查找,没找到则去操作系统中查找。
- 操作系统里查找缓存的域名和ip的映射,没有找到这区host文件中查找。
- 查找host文件,没有找到,那么将去本地dns服务器查找。
- 如果使用了转发模式,那么就一步步的向上查找isp,直到根isp。
- 如果未使用转发模式,那么就直接去根isp服务器。 这个过程就好像,你查找你女朋友的号码一样。首先先在大脑回顾一下,自己是否记得。(这就好比host文件)。不记得,然后就去手机通讯录里查找。(这就好比本地dns服务器)。还是没查到,那么就去距离自己最近的运营商服务点,如果还是没有查找到,那么直接打给运营商总公司。(这就好比是没有使用转发模式时,直接去13台根isp查找)或者自己一步一步去上层查找总运营商。(这就好比是使用转发模式时,一步步向上层查找,直到根isp)...。
浏览器DNS缓存->操作系统缓存->Hosts文件->非权威域名服务器->根域名服务器->顶级域名服务器->权威域名服务器。
根据上面的过程,我们来总结一下http请求过程。
TCP建立连接的三次握手
ack: 确定连接,syn: 连接请求。主要是确认客户端和服务端收发能力是正常的。
- 第一次握手
服务端确认,客户端发送能力是正常的,自己的接受能力是正常的。
- 第二次握手
客户端确认,服务端发送和接收能力是正常的,自己的发送和接受能力也是正常的。
- 第三次握手
服务端确认,客户端接收能力是正常的。
http报文结构
HTTP 协议在规范文档里详细定义了报文的格式,规定了组成部分,解析规则,还有处理策略,所以可以在 TCP/IP 层之上实现更灵活丰富的功能,例如连接控制,缓存管理、数据编码、内容协商等等。
HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:
- 起始行(start line):描述请求或响应的基本信息;
- 头部字段集合(header):使用 key-value 形式更详细地说明报文;
- 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。 这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。
header结束后必须有一个空行。HTTP 协议并没有规定报头部分的键值对有多少个. 空行就相当于是 "报头的结束标记", 或者 是 "报头和正文之间的分隔符".HTTP 在传输层依赖 TCP 协议, TCP 是面向字节流的. 如果没有这个空行, 就会出现 "粘包问题"。
请求行
它简要地描述了客户端想要如何操作服务器端的资源。 请求行由三部分构成:
- 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
状态行
响应报文里的起始行,在这里它不叫“响应行”,而是叫“状态行”(status line),意思是服务器响应的状态。
比起请求行来说,状态行要简单一些,同样也是由三部分构成:
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
- 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
头部字段
请求行或状态行再加上头部字段集合就构成了 HTTP 报文里完整的请求头或响应头。
- 通用报文头。可以用在请求头和响应头中。
- 请求报文头。仅能出现在请求头里,进一步说明请求信息或者额外的附加条件。
- 响应报文头。仅能出现在响应头里,补充说明响应报文的信息。
- 实体报文头。它实际上属于通用字段,但专门描述 body 的额外信息。
在http/1.1中一共规范了47种报文头字段。
一些常见报文头字段
- host: HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。表示相同ip下的不同域名,让服务器返回当前指定的host域名下的资源。
- Date 字段是一个通用字段,但通常出现在响应头里,表示 HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略。
- Server 字段是响应字段,只能出现在响应头里。它告诉客户端当前正在提供 Web 服务的软件名称和版本号。一般服务器响应头里都返回一个不相关的信息。防止被攻击。
- Content-Length,它表示报文里 body 的长度,也就是请求头或响应头空行后面数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么 body 就是不定长的,需要使用 chunked 方式分段传输。
http请求方法
请求方法是客户端发出的、要求服务器执行的、对资源的一种操作。请求方法是对服务器的“指示”,真正应如何处理由服务器来决定。 HTTP/1.1 规定了八种方法,单词都必须是大写的形式
- GET: 取资源,可以理解为读取或者下载数据;
- HEAD:获取资源的元信息。服务器不返回实体部分。
- POST:向资源提交数据,相当于写入或上传数据;
- PUT:类似 POST;
- DELETE:删除资源;
- CONNECT:建立特殊的连接隧道;
- OPTIONS:列出可对资源实行的方法;
- TRACE:追踪请求 - 响应的传输路径。
安全和幂等
- 安全。指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。
按照这个定义,只有 GET 和 HEAD 方法是“安全”的,因为它们是“只读”操作,只要服务器不故意曲解请求方法的处理方式,无论 GET 和 HEAD 操作多少次,服务器上的数据都是“安全的”。而 POST/PUT/DELETE 操作会修改服务器上的资源,增加或删除数据,所以是“不安全”的。
- 幂等。多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”。 很显然,GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的。按照 RFC 里的语义,POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的。而 PUT 是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的。
URI和URL
uri的一般形式
- scheme: 协议名,方案名。表示资源应该使用哪种协议来访问。例如http, https, ftp、ldap、file、news等。
- authority: 表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号。有时端口号会被省略。HTTP 的默认端口号是 80,HTTPS 的默认端口号是 443。
- path:标记资源所在位置。必须以
/
开头。 - query: 表示对资源附加的额外要求。 注意file协议之后,允许省略主机名,默认是主机localhost。但对于 HTTP 或 HTTPS 这样的网络通信协议,主机名是绝对不能省略的。会导致浏览器无法找到服务器。
客户端和服务器看到的 URI 是不一样的。客户端看到的必须是完整的 URI,使用特定的协议去连接特定的主机,而服务器看到的只是报文请求行里被删除了协议名和主机名的 URI。
uri的完整形式
- User:passwd@ : 身份信息,但是不推荐这样使用,泄露重要信息 。
- #fragment :片段标识符。标识URI所定位的资源内部的一个锚点,浏览器可以跳转到它指示的位置。服务器看不到#fragment。
url编码
如果url中出现了非ASCII码以外的字符或者url中保留字符,那么它将被编码。
把字符(unicode)编码成utf-8,utf-8是用1-4个字节表示的,所以每个字节转换成16进制并在前面用百分号(%)连接,最后并把每个字节转换的结果连接起来。但是在浏览器输入框中并不会显示转以后的字符。
状态码
状态码在响应报文里表示了服务器对请求的处理结果。 使用以表示网页服务器超文本传输协议响应状态的3位数字代码。
状态码的整体分类
- 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
- 2××:成功,报文已经收到并被正确处理;
- 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
- 4××:客户端错误,请求报文有误,服务器无法处理;
- 5××:服务器错误,服务器在处理请求时内部发生了错误。
常见的状态码
- 1xx 101 Switching Protocols。它的意思是客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。
- 2xx
204 No Content。它的含义与“200 OK”基本相同,但响应头后没有 body 数据。所以对于 Web 服务器来说,正确地区分 200 和 204 是很必要的。
- 3xx 301 和 302 都会在响应头里使用字段 Location 指明后续要跳转的 URI,最终的效果很相似,浏览器都会重定向到新的 URI。两者的根本区别在于语义,一个是“永久”,一个是“临时”,所以在场景、用法上差距很大。
304 Not Modified 它用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成“重定向已到缓存的文件”(即“缓存重定向”)。
- 4xx 400 Bad Request 是一个通用的错误码,表示请求报文有错误,但具体是数据格式错误、缺少请求头还是 URI 超长它没有明确说,只是一个笼统的错误。所以,在开发 Web 应用时应当尽量避免给客户端返回 400,而是要用其他更有明确含义的状态码。
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:请求头某个字段或总体太大;
- 5xx 503 Service Unavailable 表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503。
503 是一个“临时”的状态,很可能过几秒钟后服务器就不那么忙了,可以继续提供服务,所以503 响应报文里通常还会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求。
字符集与编码
编码规范
- 字库表:他主要是存放该编码对应的字符。
- 字符集:存放的是字符编码的二进制地址。他和字库表中的字符一一对应。
- 编码方式: 这个编码规范对应的编码格式。 一个二进制数据通过指定的编码方式将其转化成字符集中对应的地址,然后再在字库表中找到对应的字符。
常见的编码规范
- ASCII码:只是对应的ASCII码中的字符。
- GBK:存放日韩中全部的字符。
- ISO-8859-1: 这个编码规范中不存在中文。
- Unicode: 这个包括全球的字符。
URL编码
浏览器仅对url中的非ASCII码字符进行编码。并且也对保留字进行编码。
一般,我们从网上下东西,然后名字中有汉语,那么将使用这种编码规则进行编码。
一些思考题
- 如果拼 HTTP 报文的时候,在头字段后多加了一个 CRLF,导致出现了一个空行,会发生什么? 在header 下面第一个空行以后都会被当作body 体
- 讲头字段时说“:”后的空格可以有多个,那为什么绝大多数情况下都只使用一个空格呢? 头部多一个空格就会多一个传输的字节,去掉无用的信息,保证传输的头部字节数尽量小
- HTTP 协议允许在在请求行里使用完整的 URI,但为什么浏览器没有这么做呢? 因为请求头部字段中host已经标识了请求的主机名,请求行中也表示了请求的协议了。所以为了减少传输量,没必要。
- URI 的查询参数和头字段很相似,都是 key-value 形式,都可以任意自定义,那么它们在使用时该如何区别呢? query参数针对的是资源(uri),而字段针对的是本次请求,也就是报文。 一个是长期、稳定的,一个是短期、临时的。
- 你在开发 HTTP 客户端,收到了一个非标准的状态码,比如 4××、5××,应当如何应对呢? 给个错误页面、或者弹窗报个错误,然后做跳转。
- 你在开发 HTTP 服务器,处理请求时发现报文里缺了一个必需的 query 参数,应该如何告知客户端错误原因呢? http响应报文一般都是200,也有400的,并且在响应体中给出提示。