Quería crear una pequeña aplicación web independiente en Go, lo opuesto a una aplicación web normal donde los recursos se servirían por separado a través de un servidor CDN o HTTP como Nginx.
Sin embargo, si el rendimiento no es una preocupación crítica o la aplicación está diseñada para poco tráfico, el uso de una aplicación independiente simplifica la implementación y distribución porque es solo un binario ejecutable.
Hay varios paquetes disponibles para incorporar recursos en una aplicación Go:
No profundizaré en los detalles de cada biblioteca, pero prefiero el enfoque bindata debido a su facilidad de uso y soporte activo.
Primero, creemos un index.html
dentro del directorio frontend/
de tu proyecto:
<html> <body> Hello, World! </body> </html>
Ahora que tenemos una configuración de proyecto y un recurso estático para probar, instalemos bidata usando el comando:
go get -u github.com/jteeuwen/go-bindata/...
Estamos listos para ejecutar el código backend de la aplicación web. Cree un archivo main.go
y copie el siguiente código:
package main import ( "bytes" "io" "net/http" ) //go:generate go-bindata -prefix "frontend/" -pkg main -o bindata.go frontend/... func static_handler(rw http.ResponseWriter, req *http.Request) { var path string = req.URL.Path if path == "" { path = "index.html" } if bs, err := Asset(path); err != nil { rw.WriteHeader(http.StatusNotFound) } else { var reader = bytes.NewBuffer(bs) io.Copy(rw, reader) } } func main() { http.Handle("/", http.StripPrefix("/", http.HandlerFunc(static_handler))) http.ListenAndServe(":3000", nil) }
Línea importante en este código:
//go:generate go-bindata -prefix "frontend/" -pkg main -o bindata.go frontend/...
La línea anterior nos permite ejecutar el comando go-bindata
cuando se llama go generate
. A partir de la versión 1.4, puedes ejecutar comandos personalizados durante la fase de generación. Es sólo cuestión de agregar //go:generate command argument...
a su archivo go.
La línea de comando go-bindata
tiene varios parámetros, así que consulte la documentación sobre cómo usarla. En nuestro caso decimos:
-prefix "frontend/"
define parte de la ruta para estática
-pkg main
define el nombre del paquete utilizado en el código generado
-o bindata.go
define el nombre del archivo generado
Después de ejecutar el comando go generate
, debería ver un archivo generado llamado bindata.go
. La estructura de su proyecto debería verse así:
. │ ├── bindata.go (auto-generated file) ├── frontend │ └── index.html └── main.go
La lógica para entregar archivos estáticos está en la función static_handler
, que recibe la solicitud y verifica si la ruta coincide con la ruta estática. La verificación se realiza mediante la función Asset
, exportada automáticamente por el usuario bindata.go
. Si el recurso no existe, devolvemos un 404
; de lo contrario, devolvemos el contenido del recurso.
El resto del código es para crear la aplicación web y vincular nuestra plantilla static_handler
para que coincida con todas las solicitudes entrantes de /
. Si tiene problemas para comprender este código, consulte la documentación oficial de Go para http package
.
Como recordatorio rápido de cómo Go maneja los paquetes, todos los identificadores se exportarán automáticamente a otros paquetes con el mismo nombre si la primera letra del nombre del identificador comienza con una letra mayúscula.
Según esta regla, el archivo bindata.go
proporciona la función Asset
para el paquete main
. Esto carga y devuelve un activo para el nombre de pila. Devuelve un error si no se puede encontrar el recurso o no se puede cargar.