HTTP/2 Server Push mit nginx

Donnerstag, 27.Dez 2018

Eines der interessantesten Features, die HTTP/2 mitbringt ist die Möglichkeit vom Server ausgelöst Files zum Client zu übertragen.

Webseiten benötigen bekanntermaßen zig Ressourcen (CSS, JS, Bilder, usw.), die bislang (HTTP 1.x) über eigene Requests, die der Browser absetzt, übertragen werden. Jeder Request benötigt zusätzlich Zeit für den Verbindungsaufbau und die Datenübertragung, bei HTTPS ist dieser Overhead noch größer als bei HTTP.

Bei jeder Webseite gibt es Ressourcen, die immer benötigt werden, meist CSS, Javascripts oder auch das Favicon, um die zusätzlichen Requests zu reduzieren hat man im Wesentlichen zwei Möglichkeiten. Entweder man liefert die Ressourcen inline aus, oder man setzt HTTP Server Push mit HTTP/2 ein. Das Inline-Bereitstellen ist nur für kleine Datenmengen interessant, es bewirkt zwar beim ersten Aufruf einen Geschwindigkeitsvorteil, hebelt aber Caching-Mechanismen aus und ist für weitere kontraproduktiv.

Nginx Konfiguration
  • mindestens nginx 1.13.9 wird benötigt
  • HTTP/2 muss aktiviert werden
  • Verschlüsselung ist Voraussetzung, ohne SSL kein HTTP/2

In der nginx Konfiguration muss man folgende Einstellungen vornehmen:

server {
    listen 443 ssl http2;

    ssl_certificate cert.pem;
    ssl_certificate_key key.pem;

    root /data/www/html;

    http2_push /style.css;
    http2_push /js.js;
}

Die http2_push Direktive veranlasst in diesem Fall, dass die Beiden Dateien style.css und js.js vorab gesendet werden.

Folglich alles JS und CSS via Push ausliefern und gut ist? Keineswegs ...

Fallstricke

http2_push bewirkt, dass jene Dateien vorab gesendet werden, und zwar immer, egal ob Bild, HTML, CSS, JS, somit muss man unbedingt die zu pushenden Ressourcen eingrenzen.

location ~ \.html$ {
    http2_push /style.css;
    http2_push /js.js;
}

In diesem Fall werden die beiden Dateien nurmehr für .html Dateien gepushed. Diese Lösung ist besser, aber bei größeren Applikation kann die Liste, wann eine bestimmte Datei gepushed werden soll oder nicht, ziemlich lange und aufwändig zu pflegen sein. Zudem ist es wenig praktikabel bei Releases die Webserverkonfiguration zu ändern, oder den Webserver neu zu starten. Oft beinhalten Pfade zu JS oder CSS Dateien auch eine Versionsinformation, spätestens dann wird die oben angeführte Variante uninteressant.

Steuerung durch die Applikation

Die beste Variante wäre, wenn man das Server Push aus der Applikation steuern könnte, nginx kann die Link Header abfangen und damit das Server Push auslösen, dies aktiviert man mit der http2_push_preload Direktive.

Im zweiten Schritt muss die Applikation für alle Ressourcen, die gepushed werden sollen, die Link Header hinzufügen, z.B.:

Link: </style.css>; as=style; rel=preload, </js.js>; as=script; rel=preload

Des Weiteren sollte der Push nur einmal pro Session erfolgen, da der Browser die Dateien Cached, sobald die Ressourcen einmal durch den Browser gecached wurden, ist das Push nicht mehr notwendig. Es empfiehlt sich also ein Cookie zu setzen, nachdem das Push erfolgt ist.

Test

Man testet die Konfigration entweder mit der Developer Console oder mit nghttp, ein Comanndline HTTP/2 Client.

ServerPush1

Anhand der Initiator Spalte sieht man, bei den einzelnen Ressourcen, wer diese angefordert hat, bei den JS bzw. CSS Dateien ist dort Push vermerkt. Falls die Ressourcen bereits gecached wurden ignoriert der Browser das Push.

ServerPush2

Zurück zur Übersicht