透视http协议
下面是上面的课程中的笔记
文章目录
什么是http协议
- HTTP(HyperText Transfer Protocol)超文本传输协议
- 协议
- 协议必须要有两个或多个参与者
- 协议是对参与者的一种行为约定和规范
- HTTP 是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之 间交流通信的规范,以及相关的各种控制和错误处理方式
- 传输
- 把一堆东西 从 A 点搬到 B 点,或者从 B 点搬到 A 点,数据在 A 和 B 之间双向 而不是单向流动。通常我们把先发起传输动作的 A 叫做请求方,把后接到传输的 B 叫做应 答方或者响应方
- 数据虽然是在 A 和 B 之间传输,但并没有限制只有 A 和 B 这两个角色,允许中 间有“中转”或者“接力”,A 到 B 的 传输过程中可以存在任意多个“中间人”,而这些中间人也都遵从 HTTP 协议,只要不打 扰基本的数据传输,就可以添加任意的额外功能,例如安全认证、数据压缩、编码转换等 等,优化整个传输过程。
- HTTP 是一个在计算机世界里专门用来在两点之间传输数据的约定和规范
- 超文本
- “超越了普通文本的文本”,它是文字、图片、音频和视频等的混合 体,最关键的是含有“超链接”,能够从一个“超文本”跳跃到另一个“超文本”,形成复 杂的非线性、网状的结构关系
- HTTP 是一个在计算机世界 里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
- http不是孤立的协议
- 在互联网世界里,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外,还 有一些协议依赖于 HTTP,例如 WebSocket、HTTPDNS 等。这些协议相互交织,构成了 一个协议网,而 HTTP 则处于中心地位
- 在互联网世界里,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外,还 有一些协议依赖于 HTTP,例如 WebSocket、HTTPDNS 等。这些协议相互交织,构成了 一个协议网,而 HTTP 则处于中心地位
浏览器在地址栏中输入地址后发生了哪些事情呢?
- 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;(与DNS或CDN交互)(先查本地缓存,若没有则向操作系统请求在操作系统中查询,若没有则检查本机域名解析文件 hosts,若仍没有则需向DNS服务器发送请求,或从CDN缓存中读取)
- 浏览器用 TCP 的三次握手与服务器建立连接;
- 浏览器向服务器发送拼好的报文;(http传输)
- 服务器收到报文后处理请求,同样拼好报文再发给浏览器;(http传输)
- 浏览器解析报文,渲染输出页面。
https://blog.csdn.net/qq_45147812/article/details/106429048
http报文格式
HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:
- 起始行(start line):描述请求或响应的基本信息;
- 头部字段集合(header):使用 key-value 形式更详细地说明报文;
- 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。
这其中前两部分起始行和头部字段经常又合称为“请求头”或“响应头”,消息正文又称为“实体”,但与“header”对应,很多时候就直接称为“body”。HTTP 协议规定报文必须有 header,但可以没有 body,而且在 header 之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”。
- 请求报文
- 请求行
- 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
- 注:这三个部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。
- 响应报文
- 状态行
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
- 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
- 头部字段
- 以key-value 的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;
- HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。
http协议请求方法
请求方法是客户端发出的、要求服务器执行的、对资源的一种操作,是对服务器的“指示”,真正应如何处理由服务器来决定;
- GET
- 从服务器获取资源,这个资源既可以是静态的文本、页面、图片、视频,也可以是由 PHP、Java 动态生成的页面或者其他格式的数据
- HEAD
- HEAD方法与 GET 方法类似,也是请求从服务器获取资源,服务器的处理机制也是一样的,但服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”。
- HEAD 方法可以看做是 GET 方法的一个“简化版”或者“轻量版”。因为它的响应头与 GET 完全相同,所以可以用在很多并不真正需要资源的场合,避免传输 body 数据的浪费。
- POST
- 向服务器发送数据
- PUT
- PUT 的作用与 POST 类似,也可以向服务器提交数据,但与 POST 存在微妙的不同,通常 POST 表示的是“新建”“create”的含义,而 PUT 则是“修改”“update”的含义。
- 在实际应用中,PUT 用到的比较少。而且,因为它与 POST 的语义、功能太过近似,有的服务器甚至就直接禁止使用 PUT 方法,只用 POST 方法上传数据。
- DELETE
- 指示服务器删除资源,因为这个动作危险性太大,所以通常服务器不会执行真正的删除操作,而是对资源做一个删除标记。当然,更多的时候服务器就直接不处理 DELETE 请求。
- CONNECT
- 要求服务器为客户端和另一台远程服务器建立一条特殊的连接隧道,这时 Web 服务器在中间充当了代理的角色。
- OPTIONS
- 要求服务器列出可对资源实行的操作方法,在响应头的 Allow 字段里返回。它的功能很有限,用处也不大,有的服务器(例如 Nginx)干脆就没有实现对它的支持。
- TRACE
- 多用于对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径。它的本意是好的,但存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用。
- 自定义方法
- 根据实际需求,自己发明新的方法,比如“PULL”拉取某些资源到本地,“PURGE”清理某个目录下的所有缓存数据。
安全和幂等
- 安全
- 在 HTTP 协议里,所谓的“安全”是指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。
- 只有 GET 和 HEAD 方法是“安全”的,因为它们是“只读”操作,只要服务器不故意曲解请求方法的处理方式,无论 GET 和 HEAD 操作多少次,服务器上的数据都是“安全的”。
- 而 POST/PUT/DELETE 操作会修改服务器上的资源,增加或删除数据,所以是“不安全”的。
- 幂等
- 多次执行相同的操作,结果也都是相同的
- GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的
- POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT 是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的
URI
URI 是用来唯一标记服务器上资源的一个字符串,通常也称为 URL,通常由 scheme、host:port、path 和 query 四个部分组成,有的可以省略
- scheme “方案名”或者“协议名”
- 表示资源应该使用哪种协议来访问,最常见的当然就是“http”了,表示使用 HTTP 协议。另外还有“https”,表示使用经过加密、安全的 HTTPS 协议。此外还有其他不是很常见的 scheme,例如 ftp、ldap、file、news 等
- 在 scheme 之后,必须是三个特定的字符“😕/”,它把 scheme 和后面的部分分离开。
- authority
- 表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号
- 主机名可以是 IP 地址或者域名的形式,必须要有,否则浏览器就会找不到服务器。但端口号有时可以省略,浏览器等客户端会依据 scheme 使用默认的端口号
- path
- 标记资源所在位置,采用了类似文件系统“目录”“路径”的表示方式
- URI 的 path 部分必须以“/”开始,也就是必须包含“/”,不要把“/”误认为属于前面 authority
- query
- 它在 path 之后,用一个“?”开始,但不包含“?”,表示对资源附加的额外要求
- 查询参数 query 有一套自己的格式,是多个“key=value”的字符串,这些 KV 值用字符“&”连接,浏览器和客户端都可以按照这个格式把长串的查询参数解析成可理解的字典或关联数组形式
- 片段标识符(js中使用hash来定义)
- 在基础形态上多出的部分
- 片段标识符仅能由浏览器这样的客户端使用,服务器是看不到的。也就是说,浏览器永远不会把带“#fragment”的 URI 发送给服务器,服务器也永远不会用这种方式去处理资源的片段。
- 它是 URI 所定位的资源内部的一个“锚点”或者说是“标签”,浏览器可以在获取资源后直接跳转到它指示的位置
- 客户端和服务器看到的 URI 是不一样的。客户端看到的必须是完整的 URI,使用特定的协议去连接特定的主机,而服务器看到的只是报文请求行里被删除了协议名和主机名的 URI
http响应状态码
一个十进制数字,以代码的形式表示服务器对请求的处理结果
RFC 标准把状态码分成了五类,用数字的第一位表示分类,而 0~99 不用,这样状态码的实际可用范围就大大缩小了,由 000~999 变成了 100~599。
- 客户端作为请求的发起方,获取响应报文后,需要通过状态码知道请求是否被正确处理,是否要再次发送请求,如果出错了原因又是什么。这样才能进行下一步的动作,要么发送新请求,要么改正错误重发请求
- 服务器端作为请求的接收方,也应该很好地运用状态码。在处理请求时,选择最恰当的状态码回复客户端,告知客户端处理的结果,指示客户端下一步应该如何行动。特别是在出错的时候,尽量不要简单地返 400、500 这样意思含糊不清的状态码
- 1××
- 1××类状态码属于提示信息,是协议处理的中间状态,实际能够用到的时候很少
- 101 Switching Protocols 客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了
- 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 Moved Permanently 永久重定向,表示此次请求的资源已经不存在了,需要改用改用新的 URI 再次访问
- 302 Found 临时重定向,意思是请求的资源还在,但需要暂时用另一个 URI 来访问
- 304 Not Modified 用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它不具有通常的跳转含义,但可以理解成重定向已到缓存的文件(即缓存重定向)
- 4××
- 4××类状态码表示客户端发送的请求报文有误,服务器无法处理,它就是真正的“错误码”含义了
- 400 Bad Request 是一个通用的错误码,表示请求报文有错误,但具体是数据格式错误、缺少请求头还是 URI 超长它没有明确说,只是一个笼统的错误
- 403 Forbidden 实际上不是客户端的请求出错,而是表示服务器禁止访问资源。原因可能多种多样,例如信息敏感、法律禁止等,如果服务器友好一点,可以在 body 里详细说明拒绝请求的原因
- 404 Not Found 资源在本服务器上未找到,所以无法提供给客户端
- 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 请求头某个字段或总体太大
- 5××
- 5××类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码”
- 500 Internal Server Error 一个通用的错误码
- 501 Not Implemented 表示客户端请求的功能还不支持
- 502 Bad Gateway 通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的
- 503 Service Unavailable 表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503,这是一个“临时”的状态,很可能过几秒钟后服务器就不那么忙了,可以继续提供服务,所以 503 响应报文里通常还会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求
http协议的特点
- HTTP 是灵活可扩展的,可以任意添加头字段实现任意功能,例如传输的实体数据可缓存可压缩、可分段获取数据、支持身份认证、支持国际化语言等。HTTP 最大的优点是简单、灵活和易于扩展
- HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施
- HTTP 是可靠传输协议,基于 TCP/IP 协议“尽量”保证数据的送达(http收发数据的成功率不是百分之百的)
- HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据
- HTTP 使用了请求 - 应答模式,客户端主动发起请求,服务器被动回复请求
- HTTP 本质上是无状态的(没有记忆能力),每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。HTTP 是有连接无状态,顺序发包顺序收包,按照收发的顺序管理报文。HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”
- HTTP1.1之前是无连接的,即协议不保持连接状态,每次应答后都会关闭连接(与UDP类似,但这样很影响性能),HTTP1.1改成了默认启动长连接(首部中的Connection: Keep-alive)
- HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听
- HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改
- HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间
http的数据类型和语言类型
- 数据类型表示实体数据的内容是什么,使用的是 MIME type,相关的头字段是 Accept 和 Content-Type
- 语言类型表示实体数据的自然语言,相关的头字段是 Accept-Language 和 Content-Language
- 客户端需要在请求头里使用 Accept 等头字段与服务器进行“内容协商”,要求服务器返回最合适的数据,Accept 等头字段可以用“,”顺序列出多个可能的选项,还可以用“;q=”参数来精确指定权重
数据类型:MIME type
- 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,即不透明的二进制数据
数据类型编码格式:Encoding type
- HTTP 在传输时为了节约带宽,有时候还会压缩数据,为了不要让浏览器继续“猜”,还需要有一个“Encoding type”,告诉数据是用的什么编码格式,这样对方才能正确解压缩,还原出原始的数据
- gzip:GNU zip 压缩格式,也是互联网上最流行的压缩格式
- deflate:zlib(deflate)压缩格式,流行程度仅次于 gzip
- br:一种专门为 HTTP 优化的新压缩算法(Brotli)
Accept字段与Content-Type字段
-
Accept字段标记的是客户端可理解的 MIME type,可以用“,”做分隔符列出多个类型,让服务器有更多的选择余地
-
服务器会在响应报文里用头字段Content-Type告诉实体数据的真实类型
Accept-Encoding字段与Content-Encoding字段
- Accept-Encoding字段标记的是客户端支持的压缩格式,例如上面说的 gzip、deflate 等,同样也可以用“,”列出多个,服务器可以选择其中一种来压缩数据,实际使用的压缩格式放在响应头字段Content-Encoding里
- 这两个字段是可以省略的,如果请求报文里没有 Accept-Encoding 字段,就表示客户端不支持压缩数据;如果响应报文里没有 Content-Encoding 字段,就表示响应数据没有被压缩
语言类型
- Accept-Language字段标记了客户端可理解的自然语言,也允许用“,”做分隔符列出多个类型
- 服务器在响应报文里用头字段Content-Language告诉客户端实体数据使用的实际语言类型
- 字符集在 HTTP 里使用的请求头字段是Accept-Charset,但响应头里却没有对应的 Content-Charset,要用Content-Type字段的数据类型后面用“charset=xxx”来表示
传输大文件
-
分块传输
把文件“拆开”,分解成多个小块,把这些小块分批发给浏览器,浏览器收到后再组装复原- 这种“化整为零”的思路在 HTTP 协议里就是“chunked”分块传输编码,在响应报文里用头字段“Transfer-Encoding: chunked”来表示,意思是报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送
- “Transfer-Encoding: chunked”和“Content-Length”这两个字段是互斥的,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked)
-
范围请求
允许客户端在请求头里使用专用字段来表示只获取文件的一部分,相当于是客户端的“化整为零”
- 范围请求不是 Web 服务器必备的功能,可以实现也可以不实现,所以服务器必须在响应头里使用字段“Accept-Ranges: bytes”明确告知客户端:“我是支持范围请求的”
- 如果不支持,服务器可以发送“Accept-Ranges: none”,或者干脆不发送“Accept-Ranges”字段,这样客户端就认为服务器没有实现范围请求功能
- 请求头Range是 HTTP 范围请求的专用字段,格式是“bytes=x-y”,其中的 x 和 y 是以字节为单位的数据范围
-
多段数据
http协议支持在 Range 头里使用多个“x-y”,一次性获取多个片段数据- 这种情况需要使用一种特殊的 MIME 类型:“multipart/byteranges”,表示报文的 body 是由多段字节序列组成的,并且还要用一个参数“boundary=xxx”给出段之间的分隔标记
- 多段数据的格式与分块传输也比较类似,但它需要用分隔标记 boundary 来区分不同的片段
http的连接
- HTTP 协议最初是个非常简单的协议,通信过程也采用了简单的“请求 - 应答”方式,它底层的数据传输基于 TCP/IP,每次发送请求前需要先与服务器建立连接,收到响应报文后会立即关闭连接。
- 短连接的缺点相当严重,因为在 TCP 协议里,建立连接和关闭连接都是非常“昂贵”的操作。TCP 建立连接要有“三次握手”,发送 3 个数据包,需要 1 个 RTT;关闭连接是“四次挥手”,4 个数据包需要 2 个 RTT
- 针对短连接暴露出的缺点,HTTP 协议就提出了“长连接”的通信方式,也叫“持久连接”(persistent connections)、“连接保活”(keep alive)、“连接复用”(connection reuse)
- http默认为长连接,也可以在请求头里明确地要求使用长连接机制,使用的字段是Connection,值是“keep-alive"
- 报文头里如果有“Connection: close”就意味着长连接即将关闭
- 服务器端通常不会主动关闭连接,但也可以使用一些策略
- 性能优化
- 并发连接
- 同时对一个域名发起多个长连接,用数量来解决质量的问题
- 缺点:服务器可能会承载不了这么大的压力
- 域名分片
- 多开几个域名,比如 shard1.chrono.com、shard2.chrono.com,而这些域名都指向同一台服务器 www.chrono.com,这样实际长连接的数量就又上去了,真是“美滋滋”。不过实在是有点“上有政策,下有对策”的味道
- 并发连接
http的重定向
重定向是服务器发起的跳转,要求客户端改用新的 URI 重新发送请求,通常会自动进行,用户是无感知的
- Location字段属于响应字段,必须出现在响应报文里。但只有配合 301/302 状态码才有意义,它标记了服务器要求重定向的 URI
- 浏览器收到 301/302 报文,会检查响应头里有没有“Location”。如果有,就从字段值里提取出 URI,发出新的 HTTP 请求,相当于自动替我们点击了这个链接
- 301 永久重定向,意思是原 URI 已经“永久”性地不存在了,今后的所有请求都必须改用新的 URI
- 302 临时重定向,意思是原 URI 处于“临时维护”状态,新的 URI 是起“顶包”作用的“临时工”
- 浏览器看到 301,就知道原来的 URI“过时”了,就会做适当的优化。比如历史记录、更新书签,下次可能就会直接用新的 URI 访问,省去了再次跳转的成本。搜索引擎的爬虫看到 301,也会更新索引库,不再使用老的 URI。浏览器或者爬虫看到 302,会认为原来的 URI 仍然有效,但暂时不可用,所以只会执行简单的跳转页面,不记录新的 URI,也不会有其他的多余动作,下次访问还是用原 URI
http中的cookie
- 对应响应头字段Set-Cookie和请求头字段Cookie
- 当用户通过浏览器第一次访问服务器的时候,服务器肯定是不知道他的身份的。所以,就要创建一个独特的身份标识数据,格式是“key=value”,然后放进 Set-Cookie 字段里,随着响应报文一同发给浏览器
- 浏览器收到响应报文,看到里面有 Set-Cookie,知道这是服务器给的身份标识,于是就保存起来,下次再请求的时候就自动把这个值放进 Cookie 字段里发给服务器
- 因为第二次请求里面有了 Cookie 字段,服务器就知道这个用户不是新人,之前来过,就可以拿出 Cookie 里的值,识别出用户的身份,然后提供个性化的服务
- Cookie 的有效期可以使用 Expires 和 Max-Age 两个属性来设置
- Domain和Path指定了 Cookie 所属的域名和路径
- cookie的应用
- 身份识别 保存用户的登录信息,实现会话事务
- 比如,你用账号和密码登录某电商,登录成功后网站服务器就会发给浏览器一个 Cookie,内容大概是“name=yourid”,这样就成功地把身份标签贴在了你身上。之后你在网站里随便访问哪件商品的页面,浏览器都会自动把身份 Cookie 发给服务器,所以服务器总会知道你的身份,一方面免去了重复登录的麻烦,另一方面也能够自动记录你的浏览记录和购物下单(在后台数据库或者也用 Cookie),实现了“状态保持”。
- 广告跟踪
- 例如,你上网的时候肯定看过很多的广告图片,这些图片背后都是广告商网站(例如 Google),它会“偷偷地”给你贴上 Cookie 小纸条,这样你上其他的网站,别的广告就能用 Cookie 读出你的身份,然后做行为分析,再推给你广告
- 身份识别 保存用户的登录信息,实现会话事务
http缓存机制
缓存是优化系统性能的重要手段,HTTP 传输的每一个环节中都可以有缓存
- 浏览器发现缓存无数据,于是发送请求,向服务器获取资源
- 服务器响应请求,返回资源,同时标记资源的有效期
- 浏览器缓存资源,等待下次重用
max-age: HTTP 缓存控制最常用的属性
no_store:不允许缓存,用于某些变化非常频繁的数据
no_cache:可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本
must-revalidate:如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证
- 浏览器也可以发送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新数据
例子:
资源验证
- 验证资源是否失效需要使用“条件请求”,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以复用缓存里的资源
- 验证资源是否被修改的条件有两个:“Last-modified”和“ETag”,需要服务器预先在响应报文里设置,搭配条件请求使用
http的代理
-
引入 HTTP代理后,原来简单的双方通信就变复杂了一些,加入了一个或者多个中间人,但整体上来看,还是一个有顺序关系的链条,而且链条里相邻的两个角色仍然是简单的一对一通信,不会出现越级的情况
-
指服务本身不生产内容,而是处于中间位置转发上下游的请求和响应,具有双重身份:面向下游的用户时,表现为服务器,代表源服务器响应客户端的请求;而面向上游的源服务器时,又表现为客户端,代表客户端发送请求
-
代理最基本的一个功能是负载均衡。因为在面向客户端时屏蔽了源服务器,客户端看到的只是代理服务器,源服务器究竟有多少台、是哪些 IP 地址都不知道。于是代理服务器就可以掌握请求分发的“大权”,决定由后面的哪台服务器来响应请求
-
在负载均衡的同时,代理服务还可以执行更多的功能,比如:
- 健康检查:使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用;
- 安全防护:保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载;
加密卸载:对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本; - 数据过滤:拦截上下行的数据,任意指定策略修改请求或者响应;
- 内容缓存:暂存、复用服务器响应
-
代理服务器需要用字段“Via”标明代理的身份
- Via 是一个通用字段,请求头或响应头里都可以出现。每当报文经过一个代理节点,代理服务器就会把自身的信息追加到字段的末尾,就像是经手人盖了一个章
- Via 字段只解决了客户端和源服务器判断是否存在代理的问题,还不能知道对方的真实信息
缓存代理
代理服务收到源服务器发来的响应数据后需要做两件事。第一个当然是把报文转发给客户端,而第二个就是把报文存入自己的 Cache 里
- 区分客户端上的缓存和代理上的缓存,可以使用两个新属性“private”和“public”。private”表示缓存只能在客户端保存,是用户“私有”的,不能放在代理上与别人共享。而“public”的意思就是缓存完全开放,谁都可以存,谁都可以用
- 缓存失效后的重新验证也要区分开(即使用条件请求“Last-modified”和“ETag”),“must-revalidate”是只要过期就必须回源服务器验证,而新的“proxy-revalidate”只要求代理的缓存过期后必须验证,客户端不必回源,只验证到代理这个环节就行了
- 缓存的生存时间可以使用新的“s-maxage”,只限定在代理上能够存多久,而客户端仍然使用“max_age
例子
- 客户端缓存代理新增两个属性,“max-stale”和“min-fresh”
- “max-stale”的意思是如果代理上的缓存过期了也可以接受,但不能过期太多,超过 x 秒也会不要。“min-fresh”的意思是缓存必须有效,而且必须在 x 秒后依然有效
例子