Kuinka käyttää Golang 1.8: n HTTP / 2 Server Push -sovellusliittymää

Golang 1.8 julkaistiin HTTP / 2-palvelimen push-ominaisuudella. Golang päivitti net / http-paketin tukemaan HTTP / 2-ominaisuutta kohdassa 1.6, ja kyseinen koodi tukee jo PUSH_PROMISE-kehystä, jota käytetään palvelimen työntämiseen, mutta 1.6: lla ei ollut sovellusliittymää tämän kehyksen lisäämiseksi. Ja sitten 1.8 sisältää kyseisen sovellusliittymän lopulta.

Kuinka käyttää Server Push -sovellusta?

http.ResponseWriterillä on ainutlaatuinen ominaisuus. Http.ResponseWriter-käyttöliittymän takana oleva rakenne on piilotettu lukittuihin menetelmiin, ja ne avattiin tyyppivalun avulla. Monet lähtevät ohjelmoijista, jotka tuntevat http.ResponseWriterin, mutta vain kymmenesosa heistä tietää sen (tutkin Golangin 1.8-julkaisujuhlissa Tokiossa).

Golang 1.7: ssä ja sitä alhaisemmissa on jo kolme piilotettua liittymää:

func-käsittelijä (w http.ResponseWriter, r * http.Request) {
    // Avaa HTTP / 1.1: n chunked-vastausominaisuus
    f, ok: = w. (http.Flusher)
    jos ok {
        f.Flush ()
    }

    // Avaa auttajatoiminto tukemaan pitkittynyttä kyselyä (palvelimen lähettämät tapahtumat)
    c, ok: = w. (http.CloseNotifier)
    jos ok {
        mene func () {
            {
                valitse {
                tapaus <-c.CloseNotify ():

                }
            }
        } ()
    }

    // Avaa alhaisen tason pistorasioiden käyttöoikeudet WebSocket-tukea varten
    h, ok: = w. (http.Hijacker)
    jos ok {
        conn, rw, virhe: = h.Hijack ()
    }
}

Golang 1.8 toteuttaa Push API: n kuten he:

func-käsittelijä (w http.ResponseWriter, r * http.Request) {
    // Avaa HTTP / 2-palvelimen työntö
    p, ok: = w. (http.Pusher)
    jos ok {
        p.Push ("/ cool_style.css", nolla)
    }
}

Voit lisätä HTTP / 2-palvelimen push-ominaisuuden lisäämällä vain yllä olevan koodin http-ohjaimen toimintoihin. Sinun ei tarvitse lisätä erityisiä kokoonpanoja toiminnon ulkopuolelle.

Jos käyttäjäagentit, jotka eivät tue HTTP / 2: ta, lähettäminen http.Pusheriin epäonnistuu (ok muuttuu vääriksi) ja Push () -menetelmäkutsu jätetään pois. Voit vain testata GODEBUG = http2server = 0 (poista HTTP2-palvelinominaisuus käytöstä).

Kuinka se toimii?

Seuraava koodi on täydellinen esimerkki palvelimen työntöominaisuuden käytöstä:

paketin pää
tuonti (
    "FMT"
    "Io / ioutil"
    "Net / http"
)
var image [] tavu
// kuvan valmistelu
func init () {
    Var err virhe
    kuva, virhe = ioutil.ReadFile ("./ image.png")
    jos virhe! = nolla {
        paniikki (err)
    }
}
// Lähetä HTML ja push-kuva
func handlerHtml (w http.ResponseWriter, r * http.Request) {
    työntäjä, ok: = w. (http.Pusher)
    jos ok {
        fmt.Println ("Push / image")
        pusher.Push ("/ kuva", nolla)
    }
    w.Header (). Lisää ("Content-Type", "text / html")
    fmt.Fprintf (w, `    `)
}
// Lähetä kuva tavallisena HTTP-pyynnönä
func handlerImage (w http.ResponseWriter, r * http.Request) {
    w.Header (). Aseta ("Content-Type", "image / png")
    w.Write (kuva)
}
func main () {
    http.HandleFunc ("/", handlerHtml)
    http.HandleFunc ("/ image", handlerImage)
    fmt.Println ("aloita http-kuuntelu: 18443")
    virhe: = http.ListenAndServeTLS (": 18443", "server.crt", "server.key", nolla)
    fmt.Println (err)
}

Kun Push () -menetelmää on kutsuttu, net / http-paketti luo pseudo HTTP-pyyntöjä HTTP-palvelimien sisälle. handlerImage () -toiminto kutsutaan pseudopyynnöllä. Sinun ei tarvitse ottaa käyttöön ylimääräistä koodia resurssien siirtämiseen. net / http käyttää nykyisiä käsittelijän toimintoja palvelimen työntöä varten.

Haluatko havaita pseudopyynnön? Voit tehdä sen tarkistamalla r.Header.Get ('User-Agent'). Näennäispyynnöissä on vain RFC: n vaatima isäntäotsikko. En ole koskaan nähnyt käyttäjän edustajia, jotka eivät lähetä User-Agent otsikkoa. Voit siirtää erilaista sisältöä tavallisella HTTP-pyynnöllä, vaikka se tarkoittaa vähemmän.

Huoli suorituskyvystä

Voit nähdä palvelinpysähdysten parantumisen selainten kehittäjätyökalujen avulla. Chrome näyttää verkon yksityiskohtaisen raportin.

Seuraava kuvakaappaus on tulos HTTP / 1.1: stä:

Tämä on tulosta HTTP / 2: sta:

Minulla on yksi potentiaalinen huolta suorituskyvystä. Ensimmäinen on ajoitus, jonka työntö suorittaa. Yritin tarkistaa Golangin toteutuksen käyttäytymisen ja ilmoitin, että:

  • Palvelimen työntö suoritetaan, kun handlerHtml () -toiminto on valmis.
  • Vaikka käytetään chunked-vastausta (http.Flusher), työntö suoritetaan, kun istunto on suljettu.

Jos HTML-tiedostot luodaan RDB: n sisällöllä ja vievät aikaa niin kauan, olisi täydellinen ajoitus käyttää palvelimen työntöä. Mutta en voi tehdä niin nykyisessä toteutuksessa.

Bug?

Yritin käyttää Push () -menetelmän toista parametria, mutta lisäämäni otsikot jätettiin huomioimatta (kuten Cache-Control). Vain handlerImage () -sovellukseen lisätyt otsikot toimivat yhdessä. Tarkastelen net / http-koodin tex-palautuksen jälkeen.