¿Cómo se sirve un archivo html estático con un servidor web go?

89

¿Cómo sirve index.html (o algún otro archivo HTML estático) utilizando un servidor web de Go?

Solo quiero un archivo HTML básico y estático (como un artículo, por ejemplo) que pueda servir desde un servidor web de Go. El HTML debería ser modificable fuera del programa go, como sería en el caso de utilizar plantillas HTML.

Este es mi servidor web que solo aloja texto codificado ("¡Hola mundo!").

package main

import (
  "fmt"
  "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello world!")
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":3000", nil)
}
nairware
fuente

Respuestas:

140

Esa tarea es muy fácil con el paquete Golang net / http.

Todo lo que necesitas hacer es:

package main

import (
        "net/http"
)

func main() {
        http.Handle("/", http.FileServer(http.Dir("./static")))
        http.ListenAndServe(":3000", nil)
}

asumiendo que los archivos estáticos están en la carpeta nombrada staticen el directorio raíz del proyecto.

Si está en la carpeta static, tendrá una index.htmlllamada de archivo http://localhost:3000/que dará como resultado la representación de ese archivo de índice en lugar de enumerar todos los archivos disponibles.

Además, llamar a cualquier otro archivo en esa carpeta (por ejemplo http://localhost:3000/clients.html) mostrará ese archivo, correctamente representado por el navegador (al menos Chrome, Firefox y Safari :))

ACTUALIZACIÓN: entrega de archivos desde una URL diferente a "/"

Si desea servir archivos, diga desde la carpeta ./publicdebajo de la URL: localhost:3000/staticdebe usar una función adicional : func StripPrefix(prefix string, h Handler) Handlercomo esta:

package main

import (
        "net/http"
)

func main() {
        http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./public"))))
        http.ListenAndServe(":3000", nil)
}

Gracias a eso, todos sus archivos de ./publicestán disponibles enlocalhost:3000/static

Sin http.StripPrefixfunción, si intenta acceder al archivo localhost:3000/static/test.html, el servidor lo buscará en./public/static/test.html

Esto se debe a que el servidor trata el URI completo como una ruta relativa al archivo.

Afortunadamente, se resuelve fácilmente con la función incorporada.

Jarema
fuente
3
¿Por qué el patrón de la manija /static/no lo es /static?
Bryce
¿Cómo sirve un archivo html estático si el archivo está en otro lugar del disco duro, fuera del proyecto por completo?
iamtoc
Lo intenté desde la ruta absoluta: / Usuarios / nombre de usuario / ruta / a / archivo, y de todos modos funcionó con éxito.
iamtoc
@Bryce, porque desea hacer coincidir el subárbol completo ( consulte también ). Con solo /staticcomo patrón (y strip-prefix), http://example.org/staticel controlador FileServer solo atenderá las solicitudes. Eso significa que las peticiones a http://example.org/static/y http://example.org/static/foo.cssetc. fallarían o ser tratado por otro controlador.
maxschlepzig
¿Es posible servir archivos estáticos junto con rutas de descanso?
Cerebro
13

Prefiero usar http.ServeFilepara esto http.FileServer. Quería deshabilitar la exploración de directorios, un 404 adecuado si faltan archivos y una manera fácil de ubicar el archivo de índice en casos especiales. De esta manera, puede colocar el binario integrado en una carpeta y servirá todo lo relativo a ese binario. Por supuesto, se puede utilizar strings.Replaceen pcaso de que tenga los archivos almacenados en otro directorio.


func main() {
    fmt.Println("Now Listening on 80")
    http.HandleFunc("/", serveFiles)
    log.Fatal(http.ListenAndServe(":80", nil))
}

func serveFiles(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.URL.Path)
    p := "." + r.URL.Path
    if p == "./" {
        p = "./static/index.html"
    }
    http.ServeFile(w, r, p)
}
jerblack
fuente
5

NO es un servidor FTP: Eso es algo diferente de lo que pretendía, que sería servir a la index.htmlpágina de inicio, como lo haría un servidor web normal. Por ejemplo, cuando voy a mydomain.com en mi navegador, quiero index.htmlrenderizar.

Eso es principalmente lo que describe " Escribir aplicaciones web " y lo que hace un proyecto como hugo (generador de sitios html estáticos).

Se trata de leer un archivo y responder con un ContentType "text / html":

func (server *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    err := server.renderFile(w, r.URL.Path)
    if err != nil {
        w.Header().Set("Content-Type", "text/html; charset=utf-8")
        w.WriteHeader(http.StatusNotFound)
        server.fn404(w, r)
    }
}

con renderFile()la lectura y establecer el tipo correcto esencialmente:

 file, err = ioutil.ReadFile(server.MediaPath + filename)
 if ext != "" {
    w.Header().Set("Content-Type", mime.TypeByExtension(ext))
 }
VonC
fuente
Quizás no hice la pregunta correctamente. ¿No proporciona esto un medio para construir un servidor de archivos, similar a un servidor FTP? Eso es algo diferente de lo que pretendía, que sería servir la página de inicio index.html, como lo haría un servidor web normal. Por ejemplo, cuando voy a mydomain.com en mi navegador, quiero que index.html se muestre. No quiero ver un directorio de archivos almacenados en el sistema de archivos del servidor web. Puedo editar la pregunta para reformularla si mi pregunta fue engañosa.
nairware
@nairware ok, he reescrito la respuesta
VonC
Entonces, ¿no hay forma de crear un sitio web clásico en Go que use páginas HTML y páginas de servidor? ¿Debe ser un sitio web estático o un sitio web basado en plantillas?
Spero
0

Esto es fácil en golang como:

package main

import (
    "log"
    "net/http"
)

func main() {
    log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("."))))
}

'

Puede hacer esto y asegurarse de mantener su archivo HTML como index.html

Nishant Raj
fuente