Hemos aprendido a utilizar el paquete net/http
para construir un sencillo servidor web en la sección anterior, pero todos los principios de trabajo son las mismas que hemos hablado en la primera sección de este capítulo .
Request: solicitar datos de los usuarios, incluyendo la POST , GET, la Cookie y la URL.
Response: datos de respuesta desde el servidor a los clientes.
Conn: conexiones entre clientes y servidores.
Handler: lógica para la gestión de solicitudes y respuestas de productos.
La siguiente imagen muestra el flujo de trabajo del servidor web de Go.
Figura 3.9 flujo de trabajo http
- Crear socket, escuchar en un puerto y esperar a los clientes .
- Aceptar peticiones de los clientes .
- Tramitar las solicitudes, leer el encabezado HTTP, si se utiliza el método POST, también es necesario para leer los datos en el cuerpo del mensaje y enviarlos a los controladores. Por último, devolver los datos de respuesta a los clientes.
Una vez que conocemos las respuestas a las preguntas siguientes , es fácil saber cómo funciona la web en Go.
- ¿Cómo escuchar un puerto?
- ¿Cómo aceptar peticiones de cliente ?
- ¿Cómo asignar controladores ?
En la sección anterior vimos que Go utiliza ListenAndServe para manejar estas etapas: inicializar un objeto de servidor , llamar a net.Listen( "tcp" , addr ) para configurar un puerto TCP de escucha y escuchar a la dirección y el puerto específico.
Vamos a echar un vistazo a el código fuente del paquete http
.
//Build version go1.1.2.
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c, err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
}
}
¿Cómo aceptamos las peticiones de un cliente después que iniciamos a escuchar en un puerto? En el código fuente , podemos ver que se llama srv.Serve(net.Listener)
para manejar peticiones de clientes. En el cuerpo de la función hay un for{}
, se acepta la solicitud, se crea una nueva conexión y, a continuación, se inicia un nuevo goroutine , y pasa los datos de solicitud a esta goroutine: go c.serve()
. Así es como Go es compatible con alta concurrencia, y cada goroutine es independiente.
¿Cómo usamos las funciones específicas para controlar las solicitudes? conn
analiza la solicitud c.ReadRequest()
al principio, y obtiene el controlador correspondiente handler : = c.server.Handler
que es el segundo argumento que pasábamos cuando llamamos ListenAndServe
. Como pasamos nil
, Go usa su manejador por defecto handler = DefaultServeMux
. Entonces, ¿qué está haciendo DefaultServeMux
aquí? Bueno, esta es la variable de enrutador en este momento, se llama a las funciones de controlador de URL específicas . ¿Hemos asignado esto? Sí, lo hicimos. Recuerde que en la primera línea se utilizó http.HandleFunc("/", sayhelloName)
. Es asi como se utiliza esta función para registrar el estado del router para la ruta "/". Cuando la dirección URL es /
, el enrutador llama a la función sayhelloName
. DefaultServeMux llama ServerHTTP para obtener la función de controlador de ruta diferente, y llama sayhelloName
en este caso. Por último , el servidor escribe los datos y la respuesta a los clientes.
Flujo de trabajo detallado:
Figura 3.10 Flujo de trabajo de manejar una petición HTTP
Creo que ahora debes saber cómo Go se ejecuta servidores web ahora.
- Indice
- Sección anterior: Armando un servidor web sencillo
- Siguiente sección: Obteniendo el paquete http