## **服务器推送** 作为HTTP/2的一个重磅新功能,我们不要简单理解字面意思,其实不是你想推,想推就能推的,服务器要遵循请求-响应这个模型,只不过服务器对同一请求可以推送多个响应。客户端在交换 `SETTINGS` 帧时,设置字段 `SETTINGS_ENABLE_PUSH(0x2)` 为1显式允许服务器推送。 在HTTP/1.x时代,其实我们已经体验过了“服务器推送”,就是资源内嵌到HTML里。服务器在响应HTML时,就已经知道浏览器会请求哪些子资源了,这时一并响应这些子资源,可以节省了服务器到浏览器以及浏览器解析再发请求的这段延迟。但是内联的问题是浏览器不会缓存这些数据,这意味要浪费很多流量,而且有缓存时网页性能还是很好的。 服务器推送解决了这个问题。服务器在接受到请求时,分析出要推送的资源,先发个 `PUSH_PROMISE` 帧给浏览器。此帧包含一个新的流ID,还有header block fragment字段,内容是请求的头部信息,可理解为服务器模拟浏览器发起请求,然后再发送各个response header和response body。浏览器收到 `PUSH_PROMISE` 帧时,根据header block fragment字段里的url,可以知道当前有没有缓存,从而判断是否要接收。如果不要,浏览器就要发送个 `RST_STREAM` 来终止服务器推送。 如果浏览器不要这个推送,就会出现浪费流量的现象,因为整个过程都是异步的,在服务器接收到`RST_STREAM`时,响应很有可能部份发出或者全部发出了。这种情况只能视场景而定,若是流量浪费不能容忍,我们可以使用prefetch来替代,让浏览器尽早发现需要的资源,而HTTP/2中创建新的请求并不需要多少时间,所以大概多了个RTT的时间。