Cómo utilizar la API de inserción de servidor HTTP / 2 de Golang 1.8

Golang 1.8 se lanzó con la función de inserción de servidor HTTP / 2. Golang actualizó el paquete net / http para admitir la función HTTP / 2 en 1.6 y ese código ya admitía el marco PUSH_PROMISE que se usa para la inserción del servidor, pero 1.6 no tenía API para generar ese marco. Y luego, 1.8 contiene esa API finalmente.

¿Cómo usar Server Push?

http.ResponseWriter tiene una característica única. La estructura detrás de la interfaz http.ResponseWriter tiene métodos bloqueados ocultos, y se desbloquearon a través de la conversión de tipos. Muchos programadores van familiarizados con http.ResponseWriter, pero solo una décima parte lo sabe (investigué en la fiesta de lanzamiento de Golang 1.8 en Tokio).

Golang 1.7 y versiones anteriores ya tienen tres interfaces ocultas:

manejador de funciones (w http.ResponseWriter, r * http.Request) {
    // Desbloquea la función de respuesta fragmentada de HTTP / 1.1
    f, ok: = w. (http.Flusher)
    si está bien {
        f.Flush ()
    }

    // Desbloquee la función auxiliar para admitir sondeo largo fragmentado (Eventos enviados por el servidor)
    c, ok: = w. (http.CloseNotifier)
    si está bien {
        ir a func () {
            para {
                seleccione {
                case <-c.CloseNotify ():

                }
            }
        } ()
    }

    // Desbloquee el acceso de socket de bajo nivel para admitir WebSocket
    h, ok: = w. (Secuestrador http)
    si está bien {
        conn, rw, err: = h.Hijack ()
    }
}

Golang 1.8 implementa Push API como ellos:

manejador de funciones (w http.ResponseWriter, r * http.Request) {
    // Desbloquee el servidor HTTP / 2 push
    p, ok: = w. (http.Pusher)
    si está bien {
        p.Push ("/ cool_style.css", nulo)
    }
}

Puede agregar la función de inserción del servidor HTTP / 2 simplemente agregando el código anterior dentro de las funciones del controlador http. No tiene que agregar ninguna configuración especial fuera de la función.

Si los agentes de usuario que no admiten HTTP / 2, la conversión a http.Pusher falla (se vuelve falsa), y se omiten las llamadas al método Push (). Simplemente puede probar con GODEBUG = http2server = 0 (deshabilitar la función del servidor HTTP2).

¿Cómo funciona?

El siguiente código es un ejemplo completo para usar la función de inserción del servidor:

paquete principal
importar (
    "fmt"
    "io / ioutil"
    "net / http"
)
var image [] byte
// preparando imagen
func init () {
    error var err
    image, err = ioutil.ReadFile ("./ image.png")
    if err! = nil {
        pánico (err)
    }
}
// Enviar HTML e imagen de inserción
func handlerHtml (w http.ResponseWriter, r * http.Request) {
    empujador, ok: = w. (http.Pusher)
    si está bien {
        fmt.Println ("Push / image")
        pusher.Push ("/ image", nil)
    }
    w.Header (). Add ("Tipo de contenido", "text / html")
    fmt.Fprintf (w, `    `)
}
// Enviar imagen como solicitud HTTP habitual
Func handlerImage (w http.ResponseWriter, r * http.Request) {
    w.Header (). Set ("Content-Type", "image / png")
    w.Write (imagen)
}
func main () {
    http.HandleFunc ("/", handlerHtml)
    http.HandleFunc ("/ image", handlerImage)
    fmt.Println ("comenzar a escuchar http: 18443")
    err: = http.ListenAndServeTLS (": 18443", "server.crt", "server.key", nil)
    fmt.Println (err)
}

Después de llamar al método Push (), el paquete net / http crea pseudo solicitudes HTTP dentro de los servidores HTTP. La función handlerImage () se llama con la pseudo solicitud. No tiene que implementar ningún código adicional para impulsar los recursos. net / http reutiliza las funciones de controlador existentes para la inserción del servidor.

¿Quieres detectar pseudo solicitud? Puede hacerlo marcando r.Header.Get ('User-Agent'). Las pseudo solicitudes solo tienen un encabezado Host requerido por RFC. Nunca he visto ningún agente de usuario que no envíe el encabezado User-Agent. Puede enviar contenido diferente con una solicitud HTTP normal aunque eso signifique menos.

Preocupación por el rendimiento

Puede ver la mejora de la inserción del servidor a través de las herramientas de desarrollo de los navegadores. Chrome muestra un informe detallado de la red.

La siguiente captura de pantalla es el resultado de HTTP / 1.1:

Este es el resultado de HTTP / 2:

Tengo una posible preocupación sobre el rendimiento. El primero es el momento en que se realiza el empuje. Traté de verificar el comportamiento de la implementación de Golang y notifiqué que:

  • La inserción del servidor se realiza después de completar la función handlerHtml ().
  • Incluso si se utiliza la respuesta fragmentada (http.Flusher), la inserción se realiza cuando se cierra la sesión.

Si los archivos HTML se generaran con contenido de RDB y tomaran tanto tiempo, sería un momento perfecto para usar el empuje del servidor. Pero no puedo hacer eso con la implementación actual.

¿Insecto?

Traté de usar el segundo parámetro del método Push (), pero los encabezados que agregué fueron ignorados (como Cache-Control). Solo los encabezados que se agregaron en handlerImage () funcionan colectivamente. Comprobaré el código de red / http después del envío de devolución de texto.