aligned chapter 3 from https://github.com/Jackgris/build-web-application-with-golang_ES
This commit is contained in:
9
es/03.0.md
Normal file
9
es/03.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
#3 Conocimientos básicos sobre la Web
|
||||
|
||||
La razón por la que usted esta leyendo este libro, es porque esta buscando aprender a desarrollar aplicaciones web con Go. Como dije antes, Go nos provee muchos paquetes con un gran potencial como es el `http`. Este nos ayudará mucho cuando queramos desarrollar aplicaciones web. En los siguientes capítulos te voy a enseñar todo lo que necesita saber, en este capítulo vamos a hablar sobre algunos conceptos sobre la web y como correr aplicaciones web en Go.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Capítulo anterior: [Capitulo 2 Resumen](02.8.md)
|
||||
- Siguiente sección: [Principio para el trabajo en la Web](03.1.md)
|
||||
155
es/03.1.md
Normal file
155
es/03.1.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 3.1. Principios para el trabajo en la Web
|
||||
|
||||
Cada vez que abra su navegador , escriba algun direccion URL y pulse ENTER, entonces usted verá hermosas páginas web que aparecen en pantalla. ¿Pero usted sabe lo que está sucediendo detrás de esta simple acción ?
|
||||
|
||||
Normalmente, el navegador es un cliente , después de teclear la URL , envía peticiones a un servidor DNS, para obtener la dirección IP de la URL. Luego de encontrar el servidor en esta dirección IP , pide las conexiones TCP de configuración. Cuando el navegador finalizó el envío de peticiones HTTP , servidor se inicia el manejo de sus paquetes de solicitud , y luego regresar los paquetes de respuesta HTTP en tu navegador . Por último , el explorador representa cuerpos de las páginas web , y se desconecta del servidor .
|
||||
|
||||

|
||||
|
||||
Figura 3.1 Procesos de usuarios que visitan una página web
|
||||
|
||||
Un servidor web también conocido como un servidor HTTP , utiliza el protocolo HTTP para comunicarse con los clientes . Todos los navegadores web pueden ser vistos como clientes.
|
||||
|
||||
Podemos dividir los principios de trabajo de Internet en los pasos siguientes :
|
||||
|
||||
- El cliente utiliza el protocolo TCP / IP para conectarse al servidor .
|
||||
- El cliente envía paquetes de solicitud HTTP al servidor.
|
||||
- El servidor devuelve los paquetes de respuesta HTTP para el cliente , si los recursos de petición incluyen scripts dinámicos , el servidor llama al motor de scripts primero .
|
||||
- El cliente se desconecta del servidor, comienza renderizado HTML.
|
||||
|
||||
Este es un sencillo flujo de trabajo de asuntos HTTP , observe que el servidor despues de un tiempo cierra las conexiones de datos que se envían a los clientes, y espera a que la próxima petición.
|
||||
|
||||
## URL y la resolución de DNS
|
||||
|
||||
Siempre estamos utilizando URL para acceder a páginas web , pero ¿sabes cómo funciona el URL ?
|
||||
|
||||
El nombre completo de la dirección URL es Uniform Resource Locator , esto es para la descripción de recursos en Internet. Su forma básica como sigue .
|
||||
```
|
||||
esquema://host[:port #]/ruta/.../[? cadena de consulta ][# ancla ]
|
||||
esquema: asignación de protocolo subyacente (como HTTP , HTTPS, FTP )
|
||||
host: IP o nombre de dominio del servidor HTTP
|
||||
puerto#: puerto por defecto es 80 , y se puede omitir en este caso.
|
||||
Si desea utilizar otros puertos , debe especificar qué puerto . Por ejemplo ,
|
||||
http://www.cnblogs.com:8080/
|
||||
ruta: recursos de trayectoria
|
||||
datos: la cadena de consulta se envían al servidor
|
||||
ancla Ancla
|
||||
```
|
||||
DNS es la abreviatura de Sistema de nombres de dominio , que es el sistema de nombres de servicios informáticos en red , convierte nombres de dominio a direcciones IP reales , al igual que un traductor.
|
||||
|
||||

|
||||
|
||||
Figura 3.2 Principios de funcionamiento de DNS
|
||||
|
||||
Para entender más acerca de su principio de funcionamiento , veamos en detallado el proceso de resolución de DNS de la siguiente manera.
|
||||
|
||||
1. Después de escrito el nombre de dominio www.qq.com en el navegador , el sistema operativo comprueba si hay alguna relación de correspondencia en el archivo hosts para el nombre de dominio , si es así, termina la resolución de nombres de dominio.
|
||||
2. Si no hay relación de proyección en el fichero hosts , el sistema operativo comprueba si hay alguna caché en el DNS, si es así, terminó la resolución de nombres de dominio.
|
||||
3. Si no hay relación de proyección de los anfitriones y la caché de DNS , el sistema operativo busca el primer servidor de resolución de DNS en la configuración de TCP / IP, que es el servidor DNS local en este momento. Cuando el servidor DNS local recibió consulta, si el nombre de dominio que desea consultar está contenida en la configuración local de los recursos regionales , a continuación, devuelve los resultados al cliente . Esta resolución DNS es autoritativo .
|
||||
4. Si el servidor DNS local no contiene el nombre de dominio , y hay una relación de correspondencia en la memoria caché , el servidor DNS local devuelve este resultado a cliente. Esta resolución DNS no está autorizado.
|
||||
5. Si el servidor DNS local no puede resolver el nombre de dominio , ya sea por la configuración de los recursos regionales o caché , que se mete en el próximo paso depende de la configuración del servidor DNS local. Si el servidor DNS local no permite el modo de avance , envía la solicitud a la raíz del servidor DNS, a continuación, devuelve la dirección IP del servidor DNS de nivel superior para saber el nombre de dominio , .com en este caso. Si el primer servidor DNS de nivel superior no sabe , envía la solicitud al siguiente servidor DNS de primer nivel hasta el que sabe el nombre de dominio . A continuación, el servidor DNS de nivel superior le pregunta al siguiente servidor DNS de nivel para qq.com , luego encuentra el www.qq.com en algunos servidores.
|
||||
- Si el servidor DNS local habilita seguir adelante, envía la solicitud al servidor DNS de nivel superior , si el servidor DNS de nivel superior también no sabe el nombre de dominio , a continuación, seguira enviando solicitudes a nivel superior.
|
||||
- Si el servidor DNS local permite a modo de avance , la dirección IP del servidor de nombre de dominio devuelve al servidor DNS local , y el servidor local envía a los clientes.
|
||||
|
||||
Sea que el cliente DNS local habilite o no el redireccionamiento, la dirección IP del dominio siempre se retornará al serviror local de DNS, y el servidor local DNS se lo enviará de vuelta al cliente
|
||||
|
||||

|
||||
|
||||
Figura 3.3 DNS flujo de trabajo de resolución.
|
||||
|
||||
`Proceso de consulta recursiva significa que las solicitudes de información están cambiando en el proceso, encambio las solicitudes de información no cambian en el proceso de consulta iterativa .`
|
||||
|
||||
Ahora sabemos que los clientes obtendran direcciones IP , al final, por lo que los navegadores estan comunicandose con los servidores a través de las direcciones IP.
|
||||
|
||||
## Protocolo HTTP
|
||||
|
||||
Protocolo HTTP es la parte fundamental de los servicios web. Es importante saber lo que es el protocolo HTTP antes de entender cómo funciona la web.
|
||||
|
||||
HTTP es el protocolo que se utiliza para la comunicación entre navegadores y servidores web , se basa en el protocolo TCP , y por lo general utilizan el puerto 80 en el servidor web. Es un protocolo que utiliza el modelo de petición-respuesta , los clientes envían peticiones y respuestas a los servidores. De acuerdo con el protocolo HTTP , los clientes siempre cnfiguran una nueva conexión y envian una petición HTTP al servidor en cada asunto . Si el servidor no es capaz de conectar con el cliente de forma proactiva , a una llamada de conexión. La conexión entre el cliente y el servidor puede ser cerrada por cualquier lado . Por ejemplo , usted puede cancelar su tarea de descarga y conexión HTTP. Se desconecta del servidor antes de que termine la descarga.
|
||||
|
||||
El protocolo HTTP no tiene estado, lo que significa que el servidor no tiene idea acerca de la relación entre dos conexiones , a pesar de que son ambos de un mismo cliente . Para solucionar este problema, las aplicaciones web usan Cookies para mantener el estado sostenible de conexiones.
|
||||
|
||||
Por esta causa, debido a que el protocolo HTTP se basa en el protocolo TCP , todos los ataques TCP afectarán a la comunicación HTTP en el servidor , como por ejemplo SYN Flood, DoS y DDoS .
|
||||
|
||||
### Paquete de solicitud HTTP (información del navegador).
|
||||
|
||||
Solicitar paquetes tienen tres partes: la línea de petición , solicitud de encabezado y cuerpo . Hay una línea en blanco entre la cabecera y el cuerpo.
|
||||
```
|
||||
GET/domains/ejemplo/HTTP/1.1 // línea de solicitud : método de la petición , la dirección URL , el protocolo y su versión.
|
||||
Host: www.iana.org / / nombre de dominio
|
||||
User-Agent : Mozilla/5.0 (Windows NT 6.1 ) AppleWebKit/537.4 ( KHTML , like Gecko ) información Chrome/22.0.1229.94 Safari/537.4 / / navegador
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0,9,*/*;q=0.8 // mina que los clientes pueden aceptar
|
||||
Accept- Encoding : gzip , desinfla , compresión SDCH / / arroyo
|
||||
Accept- Charset : UTF- 8 , * ; q = 0.5 / / conjunto de caracteres en el lado del cliente
|
||||
// Línea en blanco
|
||||
// Cuerpo , los argumentos de recursos solicitud (por ejemplo , los argumentos de la POST )
|
||||
```
|
||||
Utilizamos fiddler que obtener la siguiente información de la solicitud.
|
||||
|
||||

|
||||
|
||||
Figura 3.4 Información de método GET capturado por fiddler
|
||||
|
||||

|
||||
|
||||
Figura 3.5 Información de método POST capturado por fiddler
|
||||
|
||||
**Podemos ver que el método GET no tiene cuerpo de la solicitud que el POST hace.**
|
||||
|
||||
Hay muchos métodos que puede utilizar para comunicarse con los servidores de HTTP ; GET, POST , PUT , DELETE son los 4 métodos básicos que utilizamos. Una URL representa un recurso en la red, por lo que estos 4 métodos significan consultar, cambiar , agregar y eliminar operaciones. GET y POST son los más utilizados en HTTP. GET anexa a la dirección URL y los usos ? para romper ellos , usos y entre los argumentos , como EditPosts.aspx ? name = test1 & id = 123456. POST pone los datos en el cuerpo de la petición , porque el URL tiene limitación de longitud por los navegadores , por lo que POST puede presentar muchos más datos que obtenga el método. También, cuando pasamos nuestro nombre de usuario y contraseña , no queremos que este tipo de información aparesca en la URL , por lo que utilizamos la POST para mantenerlos invisibles.
|
||||
|
||||
### Paquete de respuesta HTTP (información del servidor)
|
||||
|
||||
Vamos a ver qué tipo de información se incluye en los paquetes de respuesta.
|
||||
```
|
||||
HTTP/1.1 200 OK // estado
|
||||
Server : nginx/1.0.8 // web server y su versión en el equipo servidor
|
||||
Date:Date: Tue, 30 Oct 2012 04:14:25 GMT // tiempo respondió
|
||||
Content-Type : text / html // tipo de datos que responde
|
||||
Transfer-Encoding: chunked // significa que los datos se envían en fragmentos
|
||||
Conexión : keep-alive // mantener la conexión
|
||||
Content-Length: 90 // longitud del cuerpo
|
||||
// Línea en blanco
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... // cuerpo del mensaje
|
||||
```
|
||||
La primera línea se llama línea de estado , que tiene la versión de HTTP, el código de estado y el mensaje de estado.
|
||||
|
||||
El código de estado indica al cliente que es el servidor HTTP esta a la expectativa. En HTTP/1.1 , definimos 5 tipos de código de estado.
|
||||
|
||||
- 1xx Informational
|
||||
- 2xx Success
|
||||
- 3xx Redirection
|
||||
- 4xx Client Error
|
||||
- 5xx Server Error
|
||||
|
||||
Vamos a ver más ejemplos sobre los paquetes de respuesta, 200 significa servidor respondió correctamente, 302 significa la redirección .
|
||||
|
||||

|
||||
|
||||
Figura 3.6 La información completa al visitar un sitio web
|
||||
|
||||
### HTTP no tiene estado y la conexion: keep-alive
|
||||
|
||||
Sin Estado no significa que el servidor no tiene la capacidad para mantener una conexión, en otras palabras, el servidor no distingue una relación entre dos peticiones .
|
||||
|
||||
En HTTP/1.1 , Keep-alive se utiliza como valor predeterminado , si los clientes tienen más solicitudes , van a utilizar la misma conexión para muchas peticiones diferentes .
|
||||
|
||||
Observe que Keep Alive no puede mantener una conexión siempre, el software que se ejecuta en el servidor tiene cierto tiempo para mantener la conexión , y usted puede cambiarlo.
|
||||
|
||||
## Solicitar instancia
|
||||
|
||||

|
||||
|
||||
Figura 3.7 Todos los paquetes para abrir una página Web
|
||||
|
||||
Podemos ver todo el proceso de comunicación entre el cliente y el servidor de imagen superior . Usted puede notar que hay muchos archivos de recursos en la lista , se les llama archivos estáticos, y Go ha especializado métodos de procesamiento de estos archivos .
|
||||
|
||||
Esta es la función más importante de los navegadores , solicitud de una URL y obtener datos de los servidores web , y luego representar HTML para una buena interfaz de usuario. Si encuentra algún archivo en el DOM , como archivos CSS o JS , los navegadores solicitarán estos recursos desde el servidor nuevamente, hasta que todos los recursos terminen apareciendo en la pantalla.
|
||||
|
||||
Reducir los tiempos de solicitud HTTP es uno de los métodos que mejora la velocidad de carga de páginas web , que está reduciendo archivos CSS y JS , se reduce la presión en los servidores web a la vez .
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Sección anterior: [Conocimientos básicos sobre la Web](03.0.md)
|
||||
- Siguiente sección: [Armando un servidor web sencillo](03.2.md)
|
||||
65
es/03.2.md
Normal file
65
es/03.2.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# 3.2 Armando un servidor web sencillo
|
||||
|
||||
Hablamos de que las aplicaciones web se basan en el protocolo HTTP, y Go permite la plena capacidad para HTTP en el paquete `net/http`, es muy fácil instalar un servidor web mediante el uso de este paquete .
|
||||
|
||||
## Uso del paquete http para configurar un servidor web
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"log"
|
||||
)
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm() //analizar argumentos , tiene que llamar a esto por su cuenta
|
||||
fmt.Println(r.Form) //imprime información en el form en el lado del servidor
|
||||
fmt.Println("path", r.URL.Path)
|
||||
fmt.Println("scheme", r.URL.Scheme)
|
||||
fmt.Println(r.Form["url_long"])
|
||||
for k, v := range r.Form {
|
||||
fmt.Println("key:", k)
|
||||
fmt.Println("val:", strings.Join(v, ""))
|
||||
}
|
||||
fmt.Fprintf(w, "Hello astaxie!") // enviar datos al lado del cliente
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", sayhelloName) // define la ruta
|
||||
err := http.ListenAndServe(":9090", nil) // establece el puerto de escucha
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
Después de ejecutar el código anterior, el host Local empieza a escuchar en el puerto 9090.
|
||||
|
||||
Abra su navegador y visite `http://localhost:9090`, se puede ver que `Hello astaxie` está en su pantalla .
|
||||
|
||||
Vamos a intentar otra dirección con argumentos : `http://localhost:9090/?url_long=111&url_long=222`
|
||||
|
||||
Ahora veamos lo que sucedió en los dos lados de cliente y servidor .
|
||||
|
||||
Usted debe ver la siguiente información en su lado del servidor :
|
||||
|
||||

|
||||
|
||||
Figura 3.8 Información del servidor por pantalla
|
||||
|
||||
Como se puede ver, sólo tenemos que llamar a dos funciones para crear un servidor web simple .
|
||||
|
||||
Si está trabajando con PHP, es probable que desee preguntar qué necesitamos algo como Nginx o Apache , la respuesta es que no necesitamos porque GO escucha el puerto TCP por sí mismo, y la `sayhelloName` función es la función lógica como controlador en PHP .
|
||||
|
||||
Si está trabajando con Python , usted debe saber tornado , y el ejemplo anterior es muy similar a eso.
|
||||
|
||||
Si está trabajando con Ruby, usted puede notar que es como script/server en ROR .
|
||||
|
||||
Utilizamos dos funciones simples para configurar un servidor web simple en esta sección, y este servidor sencillo ya ha tenido capacidad para alta concurrencia. Vamos a hablar acerca de cómo usar esta característica en dos secciones siguientes .
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Sección anterior: [Principios para el trabajo en la Web](03.1.md)
|
||||
- Siguiente sección: [Como trabaja Go con la web](03.3.md)
|
||||
85
es/03.3.md
Normal file
85
es/03.3.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# 3.3 Como trabaja Go con la web
|
||||
|
||||
Hemos aprendido a utilizar el paquete `net/http` para construir un sencillo servidor web en el apartado anterior, pero todos los principios de trabajo son las mismas que hemos hablado en la primera sección de este capítulo .
|
||||
|
||||
## Algunos conceptos de los principios de trabajo web
|
||||
|
||||
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.
|
||||
|
||||
## Mecanismo de funcionamiento del paquete http
|
||||
|
||||
La siguiente imagen muestra el flujo de trabajo del servidor web de Go.
|
||||
|
||||

|
||||
|
||||
Figura flujo de trabajo 3.9 http
|
||||
|
||||
1. Crear socket y escucha en un puerto, esperando a los clientes .
|
||||
2. Acepta peticiones de los clientes .
|
||||
3. 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 signar a los controladores. Por último , devuelve datos de respuesta a los clientes.
|
||||
|
||||
Una vez que conocemos las respuestas a lastres 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 estos problemas : inicializar un objeto de servidor , llame 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 aceptar peticiones de cliente después de escuchar el 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.
|
||||
|
||||
Ahora, la forma de utilizar las funciones específicas para controlar las solicitudes? `conn` analiza la solicitud `c.ReadRequest()` al principio, y consegui el controlador correspondiente `handler : = c.server.Handler` que es el segundo argumento que pasábamos cuando llamamos `ListenAndServe`. Porque pasamos `nil`, por lo que Go usa su manejador controlador `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 fijar 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 usted debe saber cómo Go se ejecuta servidores web ahora.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Sección anterior: [Armando un servidor web sencillo](03.2.md)
|
||||
- Siguiente sección: [Obteniendo el paquete http](03.4.md)
|
||||
203
es/03.4.md
Normal file
203
es/03.4.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# 3.4 Obteniendo el paquete http
|
||||
|
||||
En las secciones anteriores, hemos aprendido sobre el flujo de trabajo de la web, y hablamos un poco sobre el paquete `http`. En esta sección, vamos a aprender dos funciones básicas que estan en el paquete `http`: Conn, ServeMux.
|
||||
|
||||
## goroutine en Conn
|
||||
|
||||
A diferencia de los servidores HTTP normales , Go utiliza goroutine para toda conexion que creó Conn con el fin de lograr una alta concurrencia y rendimiento, por lo que cada caso es independiente.
|
||||
|
||||
Go usa el siguiente código para esperar a nuevas conexiones de clientes .
|
||||
```
|
||||
c, err := srv.newConn(rw)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
go c.serve()
|
||||
```
|
||||
Como puede ver, se crea una goroutine para cada conexión , y se pasa el controlador que es capaz de leer los datos de solicitud a la goroutine .
|
||||
|
||||
## ServeMux personalizado
|
||||
|
||||
Utilizamos el enrutamiento por defecto en la sección anterior, cuando se habla conn.server , el router pasa los datos de solicitud como back-end al controlador.
|
||||
|
||||
El struct del router por defecto:
|
||||
```
|
||||
type ServeMux struct {
|
||||
mu sync.RWMutex //debido a la concurrencia, tenemos que utilizar mutex aquí
|
||||
m map[string]muxEntry //routers, cada asignación de cadena a un controlador
|
||||
}
|
||||
```
|
||||
El struct de muxEntry:
|
||||
```
|
||||
type muxEntry struct {
|
||||
explicit bool // exact match or not
|
||||
h Handler
|
||||
}
|
||||
```
|
||||
La interfaz de Handler:
|
||||
```
|
||||
type Handler interface {
|
||||
ServeHTTP(ResponseWriter, *Request) // routing implementer
|
||||
}
|
||||
```
|
||||
`Handler` es una interfaz, pero la función `sayhelloName` no implementar su interfaz , por eso podríamos agregarlo como controlador ? Debido a que hay otro tipo `HandlerFunc` en el paquete `http` . Llamamos `HandlerFunc` definir nuestra `sayhelloName` , así `sayhelloName` implementa el `Handler` al mismo tiempo. que es como llamamos `HandlerFunc(f)`, y la función `f` es forzado convertido al tipo `HandlerFunc`.
|
||||
```
|
||||
type HandlerFunc func(ResponseWriter, *Request)
|
||||
|
||||
// ServeHTTP calls f(w, r).
|
||||
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
|
||||
f(w, r)
|
||||
}
|
||||
```
|
||||
Cómo enrutador llama los controladores después de establecer reglas del router ?
|
||||
|
||||
El enrutador llama `mux.handler.ServeHTTP(w , r)` cuando recibe solicitudes. En otras palabras, se llama la interfaz `ServeHTTP` de los controladores.
|
||||
|
||||
Ahora, vamos a ver cómo funciona `mux.handler`.
|
||||
```
|
||||
func (mux *ServeMux) handler(r *Request) Handler {
|
||||
mux.mu.RLock()
|
||||
defer mux.mu.RUnlock()
|
||||
|
||||
// Host-specific pattern takes precedence over generic ones
|
||||
h := mux.match(r.Host + r.URL.Path)
|
||||
if h == nil {
|
||||
h = mux.match(r.URL.Path)
|
||||
}
|
||||
if h == nil {
|
||||
h = NotFoundHandler()
|
||||
}
|
||||
return h
|
||||
}
|
||||
```
|
||||
El router utiliza la URL como clave para encontrar correspondiente controlador que guarda en un mapa , y llama handler.ServeHTTP para ejecutar funciones para manejar los datos.
|
||||
|
||||
Usted debe entender el flujo de trabajo del router, y Go realmente apoya routers personalizados. El segundo argumento de ListenAndServe es para la configuración del router a medida, que es una interfaz de `Handler`. Por lo tanto , se puede utilizar cualquier router que implemente la interfaz `Handler`.
|
||||
|
||||
El siguiente ejemplo muestra cómo implementar un enrutador sencillo.
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MyMux struct {
|
||||
}
|
||||
|
||||
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
sayhelloName(w, r)
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello myroute!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := &MyMux{}
|
||||
http.ListenAndServe(":9090", mux)
|
||||
}
|
||||
```
|
||||
# Enrutamiento
|
||||
|
||||
Si tu no quieres usar un router, todavía puedes lograr lo que escribimos en la sección de arriba reemplazando el segundo argumento de `ListenAndServe` a nil, y registrando las URLS usando un `HandleFunc` función que recorre todas las URLs registradas para encontrar la mejor coincidencia, entonces debemos preocuparnos por el orden de registro.
|
||||
|
||||
código de ejemplo:
|
||||
```
|
||||
http.HandleFunc("/", views.ShowAllTasksFunc)
|
||||
http.HandleFunc("/complete/", views.CompleteTaskFunc)
|
||||
http.HandleFunc("/delete/", views.DeleteTaskFunc)
|
||||
|
||||
//ShowAllTasksFunc es usado para manejar la URL "/" que tiene por defecto todo
|
||||
//TODO agregar manejador para 404
|
||||
func ShowAllTasksFunc(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" {
|
||||
context := db.GetTasks("pending") //true cuando tu no quieres eliminar tareas
|
||||
//db es un paquete que interactua con la base de datos
|
||||
if message != "" {
|
||||
context.Message = message
|
||||
}
|
||||
homeTemplate.Execute(w, context)
|
||||
message = ""
|
||||
} else {
|
||||
message = "Method not allowed"
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
```
|
||||
Esto está bien para aplicaciones simples las cuales no necesitan ruteos parametriados, pero ¿cuándo necesitas eso? Puedes usar las herramientas o frameworks, pero como este libro está enfocado en crear aplicaciones web en Go, vamos a enseñarte como manejar ese escenario también.
|
||||
|
||||
Cuando la concidencia es hecha, se llama a la función definida en `HandleFunc`, así que supongamos que estamos escribiendo un manejador para una lista y queremos eliminar una tarea, así que la aplicación decide que función se va a llamar cuando llegue la petición `/delete/1`, entonces registramos la URL de la siguiente manera:
|
||||
`http.HandleFunc("/delete/", views.DeleteTaskFunc)`
|
||||
`/delete/1` this URL matches closest with the "/delete/" URL than any other URL so in the `r.URL.path` we get the entire URL of the request.
|
||||
```
|
||||
http.HandleFunc("/delete/", views.DeleteTaskFunc)
|
||||
//DeleteTaskFunc is used to delete a task, trash = move to recycle bin, delete = permanent delete
|
||||
func DeleteTaskFunc(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" {
|
||||
id := r.URL.Path[len("/delete/"):]
|
||||
if id == "all" {
|
||||
db.DeleteAll()
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
} else {
|
||||
id, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
err = db.DeleteTask(id)
|
||||
if err != nil {
|
||||
message = "Error deleting task"
|
||||
} else {
|
||||
message = "Task deleted"
|
||||
}
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
message = "Method not allowed"
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
```
|
||||
Enlace: https://github.com/thewhitetulip/Tasks/blob/master/views/views.go#L170-#L195
|
||||
|
||||
Este método lo que hace básicamente es que la función que maneja la URL `/delete/`, se toma la URL completa, que es `/delete/1`, se toman segmentos de la cadena y se extraen todo lo que después de la cadena de coincidencia, en este caso es `1`. Entonces usamos el paquete `strconv` para convertir la cadena en entero y eliminar la tarea con ese identificador.
|
||||
|
||||
En escenarios mas complejos también podemos utilizar este método, la ventaja es que no vamos a tener que usar herramientas de terceros, pero las herramientas de terceros tienden a ser útiles en su sentido propio. Tienes que tomar la decisión de cuál método prefieres. Ninguna respuesta es la respuesta correcta.
|
||||
|
||||
|
||||
## GO flujo de ejecución del código
|
||||
|
||||
Vamos a echar un vistazo a la lista de flujo de ejecución en conjunto.
|
||||
|
||||
- Se llama http.HandleFunc
|
||||
1. Llame HandleFunc de DefaultServeMux
|
||||
2. Llame Handle de DefaultServeMux
|
||||
3. Agregar reglas del router para mapear [cadena ] muxEntry de DefaultServeMux
|
||||
- Se llama http.ListenAndServe (": 9090 " , nil )
|
||||
1. se instancia el servidor
|
||||
2. Llama ListenAndServe del Servidor
|
||||
3. Llama net.Listen ( " tcp" , addr ) para escuchar en el puerto .
|
||||
4. Iniciar un bucle, y aceptar las solicitudes en el cuerpo del bucle.
|
||||
5. Instanciada una Conn se empieza una goroutine para cada solicitud : ir c.serve ().
|
||||
6. Lee petición de datos : w , err : = c.readRequest ().
|
||||
7. Comprueba si el controlador está vacío, si está vacíoutiliza DefaultServeMux .
|
||||
8. Llama al controlador de ServeHTTP
|
||||
9. Ejecutar código en DefaultServeMux en este caso.
|
||||
10. Elije el controlador URL y ejecutar código del controlador en esta seccion: mux.handler.ServeHTTP ( w , r)
|
||||
11. Cómo elegir handler:
|
||||
A. Normas de router de verificación para esta URL.
|
||||
B. Llamar ServeHTTP en ese controlador, si es que existe.
|
||||
C. Llamar ServeHTTP de NotFoundHandler lo contrario.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Sección anterior: [Como trabaja Go con la web](03.3.md)
|
||||
- Siguiente sección: [Resumen](03.5.md)
|
||||
11
es/03.5.md
Normal file
11
es/03.5.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# 3.5 Resumen
|
||||
|
||||
En este capítulo, presentamos HTTP, el flujo de la resolución DNS y cómo construir un servidor Web simple. Entonces hablamos de cómo Go implementa servidor web para nosotros al ver el código fuente del paquete net/http.
|
||||
|
||||
Espero que ahora conozca mucho más sobre el desarrollo web, y usted debería ver que es muy fácil y flexible crear una aplicación web en Go.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Indice](preface.md)
|
||||
- Sección anterior: [Obteniendo el paquete http](03.4.md)
|
||||
- Siguiente sección: [Formulario de entrada de los usuario](04.0.md)
|
||||
Reference in New Issue
Block a user