一 条件请求
++++++++++++ "条件请求的场景举例" ++++++++++++
1) 在'断点续传'我们讲到,当客户端已经接收了部分body体,
2) 那么'重新获取后续body'的时候,使用了'if-match'头部
3) 去'询问服务器资源'是否发生了'变化',这就是一种"条件请求"
本篇章介绍'条件请求'的'完整'用法
每个URI对应一个资源,每个资源都有一个'表述',这个表述会随着'内容协商'而不同,也会随着时间而变化
"resource"的含义是:服务器端'暴露给外界'访问的'某种'能力
通俗: 服务端的'具体'资源,而每一种具体的资源有'独有'的URI
资源的表述: 是一段对于资源'在某个特定时刻的'状态的'描述'
优点1: 获取'西安'的天气,同一个'URL'不同时刻的信息都'不相同'
优点2: 浏览器需要不同的'语言'时候,例如'本地化'和'国际化',可以得到不同'replication'
优点3: 不用修改'url'链接
② 客户端的条件请求
++++++++++ "客户端携带的条件判断信息" ++++++++++
1) 当 HTTP 请求'包含 If-XXX' 这种样式的'请求头',服务器会'对附带的条件'进行判断
2) 只有判断'指定条件为真',服务端才会'执行'请求
3) 这样的'条件请求首部'有'五'个,分别是:
If-Modified-Since、If-Unmodified-Since、If-Match、If-None-Match 和 If-Range
细节点: 只有'服务端验证成功',才会返回'资源的表述'
注意: 掌握三个'应用场景'
1) 浏览器的'缓存失效',但是'浏览器'并没有'丢弃'该缓存,还是会'发送网络请求'
2) 断点续传时候对之前已下载过的内容进行验证,看整个响应body是否发生变化,是否可以复用之前内容
3) 多个人'同时'修改同一wiki页面
1) '强'验证器要求文档的'每个字节'都相等
2) '弱'验证器只要求'文档的含义'相等
ETag 分为'强'验证器和'弱'验证器
④ 服务器的验证方式
Last-Modified和Etag的'响应头' --> 掌握两个'常见的验证器'响应头部
上一次请求返回的'Last-Modified'响应头和本次请求'If-Modified-Since'的请求头
%x --> 16'进制' x57 --> 'W' .2F --> '/' DOUBLE --> "双引号",内容为实际的'标示符'
上一次请求返回的'Etag响应头'和下一次资源请求时'If-None-Match请求头'对比
++++++++++ "客户端发起的请求头部有以下五种" ++++++++++
⑤ 缓存更新场景1
说明: '客户端'第一次请求之后,会缓存'响应',并保存'Last-Modified'和'Etag'响应头的值
说明:
1) 客户端缓存'响应',是有一个'过期时间'的
2) 如果当前时间已经'超过'过期时间,说明'缓存过期'了,已经过期的缓存也是'有作用'的
3) 在缓存过期后,客户端'再次'发起请求,会携带两个'请求头'
[1]、If-Modified-Since 为上一次返回的'Last-Modified'响应头的值
[2]、If-None-Match 为山一返回的'Etag'响应头的值
4) 服务端对比'资源没有变化',返回一个'304',告诉客户端,资源没有'发生变化'复用之前的缓存
5) 服务端经过对比,发现'资源已经改变(修改时间或etag变化)',验证器没有通过,就返回'完整'响应
+++++++++++++++ "小结" +++++++++++++++
1) 基于'未过期'缓存发起'条件请求' --> "cache from disk"
2) 基于'过期'缓存发起'条件请求' --> 资源'没有'发生变化,返回'304'状态码
3) 基于'过期'缓存发起'条件请求' --> 资源'发生'变化,返回'200'状态码,同时返回'body'
⑥ 增量更新场景2
之前案例: '多线程'下载,'讲解'过
1) client已经下载'部分 body'
2) 后续下载'body',为了防止在'两次下载期间',资源body'发生'变化
3) 在请求的时候'加入'If-Unmodified-Since和If-Match'请求头'部
4) server端对比'没有'发生变化,就传递'客户端'想要下载的'另一部分body'内容,同时返回'206'
6) server端对比'发生'变化,服务器就通过'412'状态码告诉客户端,条件验证'失败'
7) 客户端就知道'拉取'完整的响应,而不是'部分'响应,会'再发送'一次请求
说明: 上面的案例中返回'412'又进行了一次请求,总共发起了'两次'请求
延伸: 通过'Ranges'和'If-Range(Etag的值)'请求头部可以'避免两次'请求
下面演示了'服务端资源变动'发起了完整的'响应'
+++++++++++ "案例演示" +++++++++++
细节说明: 好多是'浏览器默认的行为',我们这里'显示'的用curl来'模拟'
⑦ 更新丢失场景3
++++++++ "客户端两步操作的解读" ++++++++
1) 先获取网页'资源' --> "GET请求"
2) 然后再在本地'网页'的form表单上去'修改'
3) 再把'本地修改后'的资源进行提交 --> "PUT|POST请求"
细节: 在'两次'请求过程中'资源'可能发生变化
++++++++++ "资源发生变化的例子解读 [按照时间]" ++++++++++
1)client1'先获取资源',拿到页面,在'本地修改'
2)client2也'获取资源'拿到页面,此时二者拿到的页面是'相同'的,在'本地修改'
3) 假设: client1修改的'比较快',很快去提交了,server端收到请求去修改'服务端'资源
4) 此时: 服务端最新的'资源'是client1修改的资源
5) client2才修改完,进行提交,但是'client2'是基于'某个点'修改,完全没有看到'client1'修改
6) client2'修改'也成功的话,会导致'client1'的修改被'错误'的丢失
导致:client2的修改覆盖了'client1'
解决:client2需要'先拿到'client1所作的修改
++++++++++ "解决问题的方案: 乐观锁" ++++++++++
特点: 只'允许第一个提交更新'的客户端更新资源
举例:
[1]、client1提交是'成功'的,client2再提交就让其'失败'
[2]、必须让其先获取'client1'修改后的资源'再'进行'本地修改',再'提交'修改才能成功
原因: client2没有基于'client1的修改'进行修改
解决策略:
[1]、基于'etag'条件请求,因为'资源发生变化','etag'就发生变化了
[2]、此时'条件验证器'就通不过了,客户端会'再次'获取最新的资源
说明:
[1]、同时'修改'时,client1和client2 首次通过'If-None-Match: *'
[2]、当client1先'更新资源(首次上传)'后,etag就发生变化了
[3]、client2后更新资源时,此时etag和'If-None-Match: *'校验不通过,会返回412条件不通过
⑧ nginx处理条件请求的规则
说明: 列出来nginx的'ngx_http_not_modified_filter_module'模块进行'条件验证'流程
备注: 注意处理'请求流'的先后顺序,以及'请求头'和'上一次响应头'的对比
条件'预验证器'在nginx服务端的'处理'流程
⑨ 相关解惑
+++++++++ "三种场景小结" +++++++++
注意: 不同场景的'头部'
+++++++++ "不同请求头的应用背景" +++++++++