Comment utiliser l’API HTTP / 2 Server de Golang 1.8

Golang 1.8 est sorti avec la fonctionnalité push du serveur HTTP / 2. Golang a mis à jour le paquet net / http pour prendre en charge la fonctionnalité HTTP / 2 à la version 1.6 et ce code prenait déjà en charge la trame PUSH_PROMISE utilisée pour le transfert du serveur, mais la 1.6 n’avait pas d’API pour générer cette trame. Et puis, 1.8 contient finalement cette API.

Comment utiliser Server Push?

http.ResponseWriter a une caractéristique unique. La structure derrière l'interface http.ResponseWriter a caché des méthodes verrouillées, et elles ont été déverrouillées via le transtypage. Beaucoup vont aux programmeurs familiers avec http.ResponseWriter, mais seulement un dixième d’entre eux le savent (j’ai fait des recherches lors de la soirée de lancement de Golang 1.8 à Tokyo).

Golang 1.7 et versions antérieures ont déjà trois interfaces cachées:

gestionnaire func (w http.ResponseWriter, r * http.Request) {
    // Déverrouille la fonctionnalité de réponse en bloc de HTTP / 1.1
    f, ok: = w. (http.Flusher)
    si ok {
        f.Flush ()
    }

    // Déverrouiller la fonction d'assistance pour prendre en charge la scrutation longue fragmentée (événements envoyés par le serveur)
    c, ok: = w (http.CloseNotifier)
    si ok {
        allez func () {
            pour {
                sélectionnez {
                case <-c.CloseNotify ():

                }
            }
        } ()
    }

    // Déverrouiller l'accès de socket de bas niveau pour prendre en charge WebSocket
    h, ok: = w. (http.Hijacker)
    si ok {
        conn, rw, err: = h.Hijack ()
    }
}

Golang 1.8 implémente l'API Push comme eux:

gestionnaire func (w http.ResponseWriter, r * http.Request) {
    // Déverrouillage du serveur HTTP / 2
    p, ok: = w. (http.Pusher)
    si ok {
        p.Push ("/ cool_style.css", nil)
    }
}

Vous pouvez ajouter la fonctionnalité de serveur HTTP / 2 en ajoutant simplement le code ci-dessus dans les fonctions du gestionnaire http. Vous n'avez pas besoin d'ajouter de configuration spéciale en dehors de la fonction.

Si les agents utilisateurs qui ne prennent pas en charge HTTP / 2, la conversion en http.Pusher échoue (ok devient false) et les appels de méthode Push () sont omis. Vous pouvez simplement tester avec GODEBUG = http2server = 0 (désactiver la fonctionnalité de serveur HTTP2).

Comment ça marche?

Le code suivant est un exemple complet d'utilisation de la fonction d'envoi du serveur:

paquet principal
importation (
    "fmt"
    "io / ioutil"
    "net / http"
)
var image [] octet
// préparation de l'image
func init () {
    var err error
    image, err = ioutil.ReadFile ("./ image.png")
    si err! = nil {
        panique (err)
    }
}
// Envoyer HTML et image push
func handlerHtml (w http.ResponseWriter, r * http.Request) {
    poussoir, ok: = w. (http.Pusher)
    si ok {
        fmt.Println ("Push / image")
        pusher.Push ("/ image", nil)
    }
    w.Header (). Add ("Content-Type", "text / html")
    fmt.Fprintf (w, `    `)
}
// Envoyer l'image comme une requête HTTP habituelle
func handlerImage (w http.ResponseWriter, r * http.Request) {
    w.Header (). Set ("Content-Type", "image / png")
    w.Write (image)
}
func main () {
    http.HandleFunc ("/", handlerHtml)
    http.HandleFunc ("/ image", handlerImage)
    fmt.Println ("démarrer l'écoute HTTP: 18443")
    err: = http.ListenAndServeTLS (": 18443", "server.crt", "server.key", rien)
    fmt.Println (err)
}

Une fois la méthode Push () appelée, le package net / http crée des pseudo-requêtes HTTP dans les serveurs HTTP. La fonction handlerImage () est appelée avec la pseudo demande. Vous n'avez pas besoin d'implémenter de code supplémentaire pour pousser des ressources. net / http réutilise les fonctions de gestionnaire existantes pour le transfert du serveur.

Voulez-vous détecter une pseudo demande? Vous pouvez le faire en vérifiant r.Header.Get ('User-Agent'). Les pseudo-demandes ont uniquement un en-tête d'hôte requis par RFC. Je n'ai jamais vu d'agent utilisateur n'envoyant pas d'en-tête User-Agent. Vous pouvez envoyer différents contenus avec une requête HTTP normale même si cela signifie moins.

Préoccupation concernant la performance

Vous pouvez voir l'amélioration de la poussée du serveur via les outils de développement des navigateurs. Chrome affiche un rapport détaillé du réseau.

La capture d'écran suivante est le résultat de HTTP / 1.1:

C'est le résultat de HTTP / 2:

J'ai un problème potentiel concernant les performances. Le premier est le moment où la poussée est effectuée. J’ai essayé de vérifier le comportement de l’implémentation de Golang et informé que:

  • Le serveur Push est exécuté une fois la fonction handlerHtml () terminée.
  • Même si une réponse en bloc (http.Flusher) est utilisée, le push est effectué à la fermeture de la session.

Si les fichiers HTML étaient générés avec le contenu de la base de données relationnelle et prenaient du temps, ce serait un moment idéal pour utiliser le serveur Push. Mais je ne peux pas faire cela avec la mise en œuvre actuelle.

Punaise?

J'ai essayé d'utiliser le deuxième paramètre de la méthode Push (), mais les en-têtes que j'ai ajoutés ont été ignorés (comme Cache-Control). Seuls les en-têtes ajoutés à handlerImage () fonctionnent collectivement. Je vérifierai le code net / http après l'envoi de la déclaration tex.