## **服務器推送**
作為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的時間。