关于浏览器和http的细枝末节

http、https

数字签名

加密方法分为 单钥加密、双钥加密

  • 单钥加密的加密和解密过程用的是同一套密码,秘钥的保存很重要
  • 双钥加密过程用的是两套密码,公开的公钥和不公开的私钥公钥用来加密信息,私钥用来数字签名。
    双钥加密的原理:
    1. 公钥和私钥是一一对应关系
    2. 所有的钥对都是独一无二的
    3. 用公钥可以解开私钥加密的信息,反之亦然
    4. 可以同时生成公钥私钥,但不可能通过公钥推算出私钥
  • 为了防止有人散布伪造的公钥骗取信任,就需要一个可靠的第三方机构来生成经过认证的(公钥,私钥),世界上最主要的数字服务认证商是位于美国加州的Verisign公司,它的主要业务就是分发RSA数字证书


    "数字证书"的实例:https协议.
    • 客户端向服务器发出加密请求。
    • 服务器用自己的私钥加密网页以后,连同本身的数字证书,一起发送给客户端。
    • 客户端(浏览器)的"证书管理器",有"受信任的根证书颁发机构"列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内
    • 如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。

参考:http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

ssl/tls 安全协议

SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密
有两个问题:

  1. 如何保证公钥不被篡改
    将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。

  2. 公钥加密计算量太大,如何减少耗用的时间
    每一次对话(session),客户端和服务器端都生成一个"对话密钥",用它来加密信息,由于对话秘钥是对称加密,所以速度很快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。

因此,SSL/TLS协议的基本过程是这样的:
(1) 客户端向服务器端索要并验证公钥。
(2) 双方协商生成"对话密钥"。
(3) 双方采用"对话密钥"进行加密通信。
(1)、(2)称为"握手阶段"

"握手阶段"的详细过程(握手的时候是非对称加密生成“对话秘钥”,握手之后用“对话秘钥”进行对称加密)
参考:
http://www.ruanyifeng.com/blog/2016/08/migrate-from-http-to-https.html
http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html


HTTPS与HTTP的一些区别
  • HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
  • HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
  • HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。

参考:https://www.cnblogs.com/heluan/p/8620312.html

HTTP2优点
  1. 降低延迟(多路复用),请求优先级
  2. header压缩(HTTP2.0可以维护一个字典,差量更新HTTP头部,大大降低因头部传输产生的流量)
  3. 基于HTTPS的加密协议传输,服务器推送(Nginx或Apache配置,请求link带参)

参考:https://www.cnblogs.com/heluan/p/8620312.html

TCP连接 – 三次握手、四次挥手

握手
TCP作用:快速重传,超时重传,流量控制,阻塞控制

  • 为什么需要三次握手而不是二次握手?
    如果两次握手的话,服务端传给客户端的有可能丢失而死锁:客户端发送连接请求,服务端发确认应答,这时服务端认为已经连接成功,开始发送数据,但是确认应答丢失的情况下,客户端将不知道服务端是否准备好,也不知道是否收到了自己的请求,将忽略服务端发来的任何数据,等待确认,而服务端不停的超时重发。
  • 为什么是四次挥手而不是三次挥手?
    因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
  • 为什么需要等待2MSL?
    我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
  • 如果已经建立了连接,但是客户端突然出现故障了怎么办?
    TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

参考:
https://blog.csdn.net/qq_38950316/article/details/81087809
https://baijiahao.baidu.com/s?id=1618114723935605183&wfr=spider&for=pc

XSS跨站脚本攻击与CSRF跨站请求伪造攻击:

https://blog.csdn.net/wuhuimin521/article/details/80421851

http请求方法

  • HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
  • HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
方法描述
1GET请求指定的页面信息,并返回实体主体。
2HEAD类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4PUT从客户端向服务器传送的数据取代指定的文档的内容。
5DELETE请求服务器删除指定的页面。
6CONNECTHTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7OPTIONS允许客户端查看服务器的性能。
8TRACE回显服务器收到的请求,主要用于测试或诊断。
GET与POST请求区别

参考:https://juejin.im/post/5b4e989b6fb9a04fbd1b1dbc

区别getpost
语义获取数据提交数据
请求形式请求数据放在url后面请求头(header), 请求体(body)
缓存能被缓存,以相同的URL再去GET请求会返回304、还会被浏览器缓存参数不能缓存
数据长度浏览器或服务器可能有限制
一般传送的数据量不超过2KB。
理论上无限制,服务器会限制 – 很大
数据包GET请求可以减少网络耗时先发送请求头,再发送请求体
HTTP协议本身不保存状态信息,一次请求一次响应
安全两方面的安全标准:地址参数在地址上保留,且被缓存,安全性低
不会引起服务端任何的状态变化,因此也是无害的
反之
传输类型ASCII支持多种数据类型
幂等幂等的概念是指同一个请求方法执行多次和仅执行一次的效果完全相同POST语义不是幂等的,重复请求可能会带来意想不到的后果
在这里插入图片描述

http状态码

https://www.cnblogs.com/xflonga/p/9368993.html
1xx:通知
100:Continue 客户端应重新发送初始请求
2xx:成功
200:OK
201:created 当服务器依照客户端的请求创建了一个新资源时,发送此响应代码
204:No Content 服务器拒绝对PUT、POST或者DELETE请求返回任何状态信息或表示
3xx:重定向
301:永久重定向
302:暂时重定向
304:用于有主体数据,但客户端已拥有该数据,没必要重复发送的情况
305:使用代理,不能直接访问网站,需要通过某个代理,比如访问外网需要VPN
4xx:客户端错误
400:Bad Request 请求无效,服务器无法理解用户的请求,除非进行修改
401:Unauthorized 客户端试图对一个受保护的资源进行操作,却又没有提供正确的
认证证书
403:Forbidden
    禁止访问,服务器拒绝了你的地址请求,可能你没权限访问,
    被禁止访问,无法自行解决
404:Not Found 无法找到文件,网页不存在
405:Method Not Allowd         客户端试图使用一个本资源不支持的HTTP方法(get,post),	
资源被禁止,可能是文件目录权限不够
408:请求超时,意味着你请求发送到该网站的时间比服务器准备等待的时间要长
5xx:服务端错误
500:Internal Server Error 服务器错误响应
502:Bad Gateway 只有HTTP代理会发送这个响应代码。它表明代理方面出现问题
503:Service Unavailable HTTP服务器正常,只是下层web服务服务不能正常工作。
最可能的原因是资源不足

WebSocket

https://juejin.im/post/5dd4b991e51d450818244c30

  1. 以前的方式:

(1)不管数据有没有变化,客户端轮询服务器 – 短轮询

(2)客户端请求服务器,服务器挂起有变更返回 – 长轮询

缺点:(1)浪费资源,不够实时。(2)浪费资源

WebSocket

可以做到全双工通信
ws = new WebSocket('ws://localhost:9000');

请求头:

// 与响应头 Sec-WebSocket-Accept 相对应
Sec-WebSocket-Key: 5fTJ1LTuh3RKjSJxydyifQ==
Sec-WebSocket-Version: 13	// 表示 websocket 协议的版本
Upgrade: websocket	// 表示要升级到 websocket 协议

响应头:

Connection: Upgrade
Sec-WebSocket-Accept: ZUip34t+bCjhkvxxwhmdEOyx9hE=
Upgrade: websocket

响应行(General)中可以看到状态码 status code 是 101 Switching Protocols , 表示该连接已经从 HTTP 协议转换为 WebSocket 通信协议。

浏览器的工作原理

  • 主流浏览器有五个:Internet Explorer、Firefox、Safari、Chrome 浏览器和 Opera

  • 用户界面、浏览器引擎、渲染引擎、网络、js解释器、用户界面后端、数据存储

  1. 用户界面 - 包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面。
  2. 浏览器引擎 - 在用户界面和渲染引擎之间传送指令。
  3. 渲染引擎 - 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
  4. 网络 - 用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。
  5. 用户界面后端 - 用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
  6. JavaScript 解释器。用于解析和执行 JavaScript 代码。
  7. 数据存储。这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(但是轻便)的浏览器内数据库。

参考 https://juejin.im/post/5bd96c5a5188257f96542cbf

浏览器性能优化

  • html:语义化
  • 浏览器缓存
  • 样式表放在头部(防止“白屏”),脚本放在底部(减少页面首屏出现的时)
  • 使用外部的JavaScript和CSS(文件缓存,html 文件变小)
  • 精简js (webpack)
  • 减少DNS查找
    • 当客户端DNS缓存(浏览器和操作系统)缓存为空时,DNS查找的数量与要加载的Web页面中唯一主机名的数量相同,包括页面URL、脚本、样式表、图片、Flash对象等的主机名。减少主机名的 数量就可以减少DNS查找的数量。
    • 减少唯一主机名的数量会潜在减少页面中并行下载的数量(HTTP 1.1规范建议从每个主机名并行下载两个组件,但实际上可以多个),这样减少主机名和并行下载的方案会产生矛盾,需要大家自己权衡。建议将组件放到至少两个但不多于4个主机名下,减少DNS查找的同时也允许高度并行下载。
  • 压缩组件
    从HTTP1.1开始,Web客户端可以通过HTTP请求中的Accept-Encoding头来表示对压缩的支持
    • Accept-Encoding: gzip,deflate
      如果Web服务器看到请求中有这个头,就会使用客户端列出来的方法中的一种来进行压缩。
    • Content-Encoding: gzip
      Web服务器通过响应中的Content-Encoding来通知 Web客户端。
  • 代理缓存
    • 当浏览器通过代理来发送请求时,情况会不一样。假设针对某个URL发送到代理的第一个请求来自于一个不支持gzip的浏览器。这是代理的第一个请求,缓存为空。代理将请求转发给服务器。此时响应是未压缩的,代理缓存同时发送给浏览器。现在,假设到达代理的请求是同一个url,来自于一个支持gzip的浏览器。代理会使用缓存中未压缩的内容进行响应,从而失去了压缩的机会。相反,如果第一个浏览器支持gzip,第二个不支持,你们代理缓存中的压缩版本将会提供给后续的浏览器,而不管它们是否支持gzip。
    • 解决办法:在web服务器的响应中添加vary头Web服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。因为压缩的决定是基于Accept-Encoding请求头的,因此需要在vary响应头中包含Accept-Encoding。
      vary: Accept-Encoding

浏览器的地址栏输入网址

https://www.cnblogs.com/MarcoHan/p/5295398.html
输入地址 —>> 域名解析
—>> 发起TCP三次握手
—>> 建立TCP连接后发起http请求
—>> 服务器响应http请求,浏览器得到html代码
—>> 浏览器解析html代码,并请求代码中的资源(js, css, 图片等)
—>> 浏览器进行渲染给呈现给用户
域名解析
–> 浏览器自身的DNS缓存
–> 操作系统自身的DNS缓存
–> 读取hosts文件
–> 本地域名服务器(DNS高速缓存) – 根域名服务器 – com服务器 – baidu.com服务器

浏览器缓存机制(简易版)

https://blog.csdn.net/qq_30553235/article/details/79282113

控制浏览器是读取缓存数据还是重新请求:
Expires(HTTP 1.0)当前资源的有效期
    eg: Expires: Fri, 18 Mar 2016 07:41:53 GMT
Cache-Control(HTTP 1.1)
    设置max_age,指定组件被缓存多久. 
    eg: Cache-Control: max-age=12345600
同时制定Cache-Control和Expires,则max-age将覆盖Expires头

如果Cache-Control / Expires没过期就用缓存,
如果过期了,发现有Last-Modified(响应资源最后修改时间)
get请求加上If-Modified-Since(Get方法)(本地存储文件修改时间--即第一次服务器返回时间),
和被请求资源的最后修改时间对比,
一致就返回内容空,状态304,继续使用本地的,时间不一致返回新文件,状态200

非get请求加If-Unmodified-Since,如果实体在指定时间后,没有任何修改,那么就可以直接执行该请求使用方法的对应行为. 而如果有修改,则返回一个412 Precondition Failed状态码,并且抛弃该方法对应的行为操作(GET方法除外).

Etag(服务器返回)/If-None-Match(客户端请求)
解决一些Last-Modified/If-Modified-Since所不能解决的问题
比如:
1. Last-Modified标注的最后修改只能精确到秒级,
    如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间
    
2. 如果某些文件会被定期生成,当有时内容并没有任何变化,
    但Last-Modified却改变了,导致文件没法使用缓存
    
3. 有可能存在服务器没有准确获取文件修改时间,
    或者与代理服务器时间不一致等情形

Etag:当前资源在服务器的唯一标识
Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,
一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

ETag带来的问题
ETag的问题在于通常使用某些属性来构造它,有些属性对于特定的部署了网站的服务器来说是唯一的。
当使用集群服务器的时候,浏览器从一台服务器上获取了原始组件,之后又向另外一台不同的服务器发起条件GET请求,ETag就会出现不匹配的状况。
例如:使用inode-size-timestamp来生成ETag,文件系统使用inode存储文件类型、所有者、组和访问模式等信息,在多台服务器上,就算文件大小、权限、时间戳等都相同,inode也是不同的。

最佳实践
1. 如果使用Last-Modified不会出现任何问题,
    可以直接移除ETag,google的搜索首页则没有使用ETag。
2. 确定要使用ETag,在配置ETag的值的时候,
    移除可能影响到组件集群服务器验证的属性,
    例如使用size-timestamp来生成时间戳。

缓存机制

web缓存相关标头(详细版)

https://www.cnblogs.com/zhoulujun/p/9071277.html
https://www.cnblogs.com/_franky/archive/2011/11/23/2260109.html

客户端是否有缓存?

  1. Pragma : no-cache(常规标头,http1.0+)
    对Pragma定义的唯一的伪指令,同http1.1的Cache-Control : no-cache
    优先级从高到低是 Pragma -> Cache-Control -> Expires

  2. Expires (实体标头,HTTP 1.0+)
    一个GMT时间,试图告知客户端,在此日期内,可以信任并使用对应缓存中的副本,缺点是,一但客户端日期不准确.则可能导致失效.

  3. Cache-Control : (常规标头,HTTP1.1)

  • public: (仅为响应标头)
    响应:告知任何途径的缓存者,可以无条件的缓存该响应.

  • private: (仅为响应标头)
    响应:告知缓存者
    (据我所知,是指用户代理,常见浏览器的本地缓存.用户也是指,系统用户.但也许,不应排除,某些网关,可以识别每个终端用户的情况),
    只针对单个用户缓存响应.且可以具体指定某个字段.
    如private–“username”,则响应头中,名为username的标头内容,不会被共享缓存.

  • no-cache:
    请求: 告知缓存者,必须原原本本的转发原始请求,并告知任何缓存者,别直接拿你缓存的副本,糊弄人.你需要去转发我的请求,并验证你的缓存(如果有的话).对应名词:端对端重载.

    响应: 允许缓存者缓存副本.那么其实际价值是,总是强制缓存者,校验缓存的新鲜度.一旦确认新鲜,则可以使用缓存副本作为响应.

    no-cache,还可以指定某个包含字段,比如一个典型应用,no-cache=Set-Cookie. 这样做的结果,就是告知缓存者,对于Set-Cookie字段,你不要使用缓存内容.而是使用新滴.其他内容则可以使用缓存.

  • no-store:
    请求:告知,请求和响应都禁止被缓存(也许是出于隐私考虑)
    响应:同上.

  • max-age:
    请求:强制响应缓存者,根据该值,校验新鲜性.即与自身的Age值,与请求时间做比较.如果超出max-age值,则强制去服务器端验证.以确保返回一个新鲜的响应.其功能本质上与传统的Expires类似,但区别在于Expires是根据某个特定日期值做比较.一但缓存者自身的时间不准确.则结果可能就是错误的.而max-age,显然无此问题. Max-age的优先级也是高于Expires的.

    响应:同上类似,只不过发出方不一样.

  • max-stale:
    请求:意思是,我允许缓存者,发送一个,过期不超过指定秒数的,陈旧的缓存.
    响应:同上.

  • must-revalidate(仅为响应标头)
    响应:意思是,如果缓存过了新鲜期,则必须重新验证.而不是试图返回一个不在新鲜期的缓存.与no-cache的区别在于,no-cache,完全无视新鲜期的概念.总是强制重新验证.理论上,must-revalidate更节省流量,但相比no-cache,可能并不总是那么精准.因为即使缓存者,认为是新鲜的,也不能保证服务器端没有做过更新.如果缓存者是一个缓存代理服务器,如果其试图重新验证时,无法连接上原始服务器,则也不允许返回一个不新鲜的,缓存中的副本.而是必须返回一个504 Gateway timeout.

  • proxy-revalidate(仅为响应标头)
    响应:限制上与must-revalidate类似.区别在于受体的范围.proxy-revalidate,是要排除掉用户代理的缓存的.即,其规则并不应用于用户代理的本地缓存上.

  • min-fresh(仅为请求标头)
    请求:告知缓存者,如果当前时间加上min-fresh的值,超了该缓存的过期时间.则要给我一个新的.其实个人觉得,其功能上有点和max-age类似.但是更大的是语义上的区别.

  • only-if-cached:(仅为请求标头)
    请求:告知缓存者,我希望内容来自缓存,我并不关心被缓存响应,是否是新鲜的.

  • s-maxage(仅为响应标头)
    响应:与max-age的唯一区别是,s-maxage仅仅应用于共享缓存.而不引用于用户代理的本地缓存,等针对单用户的缓存. 另外,s-maxage的优先级要高于max-age.

  • cache-extension (cache-extension是一个泛化的代称.它指所有自定义,
    或者说扩展的,指令,客户端和服务器端都可以自定义扩展Cache-Control相关的指令.)
    那么,实际上我们可以这样 Cache-Control:max-age=300, custom-directive = xxx, public.
    这样我们就定义了一个被统称为cache-extension的扩展指令.该指令如果对应的客户端或服务器端,不认识,就会忽略掉.

    扩展指令中一个常见的东西是 none-check post-check 和 pre-check. 是IE5被加入的.所以如果响应头中有这几个扩展指令,那么IE就会认得他们, 我经常在一些 为了解决 no-cache + gzip 命中ie6 JSONP 请求,导致脚本不执行bug的方案中见到这几个扩展指令,其目的是为了让IE放弃使用本地缓存. 我倒是觉得,对IE6放弃使用gzip,是更合理的做法. 当然缺点也很明显, 如果是cdn部署静态资源.显然这样做会很困难.

  • no-transform:
    请求:告知代理,不要更改媒体类型,比如jpg,被你改成png.
    响应:同上.

客户端没有缓存,调用服务端缓存?

  • Last-Modified(实体标头,HTTP1.0+)
    一个GMT时间,告知,被请求实体的最后修改时间.用于客户端校验其缓存副本是否仍然可以信任.与其相关的两个条件请求标头:

    • If-Modified-Since:(此标头,仅对Get方法有意义)
      如果实体在指定时间后,没有修改则返回一个304,否则返回一个常规的Get请求的响应(比如200).
      另外,如果该标头的值是一个非法的值,那么也同样返回一个常规的Get请求的响应.
      PS: 用户代理发起 If-Modified-Since尝试握手的条件,可能会有不同,比如IE系,如果该实体第一次响应头中包含Cache-Control:no-cache.则 IE不会使用If-Modified-Since请求资源.而其他浏览器则会. 但是如果使用Cache-Control:no-store.则所有用户代理的表现一致.都不使用If-Modified-Since(因为no-store的语义十分强烈.不允许任何缓存,这个在后续有专门介绍.)

    • If-Unmodified-Since:(GET方法除外)
      如果实体在指定时间后,没有任何修改,那么就可以直接执行该请求使用方法的对应行为.
      而如果有修改,则返回一个412 Precondition Failed状态码,并且抛弃该方法对应的行为操作.

  • Etag : (实体标头,HTTP1.1)
    通过[Mog95],( http://www.research.digital.com/wrl/publications/abstracts/95.4.html
    遗憾的是,该地址,现在似乎访问不能.)生成一段可代表实体版本的字串.默认就是一段hash + 时间戳的形式.其实我们是可以使用自己的算法来生成Etag值.比如md5.

    PS:Apache的默认Etag包含Inode,Mtime,Size三部分.而且Etag有强弱之分.比如一般的弱Etag,是以W/开头的,如:W/”abcde12”,这部分不是我们关注的焦点.因为弱Etag和强Etag的区别只在于算法.比如某种弱Etag关注的时间精度,为秒.而我们在项目中,最常见的做法是使用MD5.是一种忽略时间维度的,强Etag.为的是保证精确度.以及负载均衡设备的同步.除非我们的项目有特殊需求.但是往往我们可以根据需求,来调整算法.而不是沿用一些传统的弱Etag算法.

    这东西,是要和客户端的两个请求标头配合使用的:

  • If-Match:
    语义:如果有匹配,或者值为”*”,才可以能去执行,请求所使用的方法,所对应的行为.
    If-Match,可以看做是一个过滤器,主要应用于资源多版本共存的解决方案.比如服务器端对同一实体,有多个版本.那么客户端,即可按照指定版本来获取实体.
    If-Match的值就是对应指定版本的Etag值.这个值可以是多选的.典型的应用场景是,客户端使用put方式请求服务器端,并带有多个If-Match的值.服务器端检查所有该实体的版本.找到匹配项,就立刻更新服务器端的对应版本.如果无一匹配,则发送一个412 Precondition Failed状态码.

  • If-None-Match:
    语义:如果有任何匹配,或值是”*”,并且原始服务器存在其请求的实体,则不允许执行该请求所使用放的对应行为,如果此时,该请求使用的get,或head方法.则返回一个304状态码.以及其他一些相关的缓存控制的标头.
    与If-Match相反 .但它的典型应用,也是我们要关注的部分.支持http1.1的现代浏览器,以及web server,应用If-None-Match头用于,缓存新鲜度校验.典型应用场景就是,一但原始服务器的某个响应中包含Etag时,如果浏览器本地缓存了该实体.那么在第二次的常规的get或head请求时,就会自动带上 If-None-Match头.当原始服务器上该实体的版本对应的Etag值与之匹配时,则原始服务器会返回304状态码.然后浏览器认为本地缓存是新鲜的.则继续使用缓存的实体. 但,其实Etag的本意是版本管理.而并不是缓存有效性校验.这应该是一个衍生出来的使用方式. 而这种方式相比Last-Modified校验方式的好处是,如果我们消除时间戳部分,仅使用hash作为Etag值. 就可以方便做负载均衡同步.

  • Age(响应标头,HTTP1.1)
    Age标头,对于原始服务器来说,用于指明,当前资源被生成了多久,即存活期.而对于一个缓存代理服务器来说,它表示缓存副本,被缓存了多久.缓存代理服务器,必须生成Age头.其值以秒为单位.且可能为负值.

  • Vary(响应标头,HTTP1.1)
    Vary标头,用于列出一组响应标头,用于缓存者从其缓存副本中筛选合适的变体.举个例子来说,不同的请求方法,导致对同一资源的响应有区别.这就导致缓存者有多份缓存副本.那么Vary所列出的标头项,就是选择副本时的一个重要依据. 比如Vary:Accept-Language.那么如果新的请求中的Accept-Language标头的值,而原始请求(被缓存的那个)中并未包含与之匹配的Accept-Language的标头的话.那就必须放弃该副本.而是把请求转发到原始服务器.
    另一个Vary的典型应用是,Vary:Accept-Encoding.这样做的意义在于,某些用户使用的浏览器,可能不支持一些特定的压缩算法.那么当这个用户途径的某个共享的缓存代理服务器,所缓存的使用了某种压缩算法的响应,就不能直接返回给该用户.如果服务器端,并没有配置这个标头,那就可能产生悲剧.即用户的浏览器无法解压缩返回的资源.导致各种异常状况的出现.

范围相关标头.以及缓存的意义.

请求标头: .Range : 1000- | -1000 | 0 - Content-Length

  • Range头可以指定向服务器(并不一定总是原始服务器,比如一个缓存代理服务器)端获取范围内的数据,这种格式是很松散的,可以用”,”逗号分割范围的一种表达式.比如1-100,-1 这就表示要获取第一到100个字节,以及最后一个字节的部分.又或者 50-则表示50个字节之后的所有数据搭配可以很灵活.
    我们关心的是和缓存有关的情况,其实对于任何客户端(包括用户代理,以及各类缓存服务器)来说.如果它明确的知道自己想要某一部分范围的数据.就可以使用Range标头. 但事实上,比如对于浏览器来说,一般情况下,只有当服务器端的响应中包含Accept-Ranges:bytes标头时,才可能会在有断点续传需求的时候,自动使用Range头去请求实体.而代只有在响应中,明确出现Accept-Ranges:none时.才会完全避免客户端(包括缓存代理服务器),使用Range标头去获取部分数据.这是要区别看待的.

    PS:Range头,还可以在GET方式下与If-Unmodified-Since标头配合,进行条件请求.其行为类似于If-Range头中使用日期格式做新鲜度校验.

  • If-Range : 实体的Etag值 | date日期值.

配合Range使用的条件请求标头,该标头的值可以是被请求实体的Etag值,又或者是其Last-Modified的日期.客户端所缓存的部分数据,是新鲜的,服务器端才会,以206方式返回这部分数据.否则,以200方式返回全部数据.

  • 响应标头:.Accept-Ranges : bytes | none

用于说明,服务器是否支持范围请求.一般,我们常常为图片等资源设置Accept-Ranges:bytes标头.以便使客户端,可以使用断点续传功能.当然,这一切的前提是,客户端之前有缓存部分数据.或者换个角度说,如果服务器端明确声明,不允许缓存某个实体.那么断点续传也就无从说起了. 所以正确的服务器端配置.是一切的基础.

  • Content-Range : bytes 0-xxxx/xxxx
    标明当前服务器端返回数据的范围. /xxxx部分是总长度.

cookie和storage对比

cookie和storage对比

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值