web-dev-qa-db-fra.com

Servir la page d'accueil et le contenu statique à partir de la racine

Dans Golang, comment puis-je servir du contenu statique hors du répertoire racine tout en ayant un gestionnaire de répertoire racine pour servir la page d'accueil.

Utilisez le simple serveur Web suivant comme exemple:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", HomeHandler) // homepage
    http.ListenAndServe(":8080", nil)
}

func HomeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "HomeHandler")
}

Si je fais

http.Handle("/", http.FileServer(http.Dir("./")))

Je reçois une panique disant que j'ai deux enregistrements pour "/". Chaque exemple de Golang que j'ai trouvé sur Internet suggère de servir leur contenu statique à partir de différents répertoires, mais cela n'aide pas beaucoup pour des choses comme sitemap.xml, favicon.ico, robots.txt et d'autres fichiers qui sont des pratiques dérivées ou mandaté pour être toujours servi hors de la racine.

Le comportement que je recherche est le comportement que l'on trouve dans la plupart des serveurs Web tels qu'Apache, Nginx ou IIS, où il parcourt d'abord vos règles, et si aucune règle n'est trouvée, il recherche un fichier réel, et si aucun fichier n'est trouvé, il 404s. Je suppose qu'au lieu d'écrire un http.HandlerFunc, Je dois écrire un http.Handler qui vérifie si je fais référence à un fichier avec une extension, et si oui vérifie l'existence du fichier et sert le fichier, sinon il 404s ou sert la page d'accueil est la demande était pour "/". Malheureusement, je ne sais même pas comment commencer une telle tâche.

Une partie de moi dit que je complique énormément la situation, ce qui me fait penser que je manque quelque chose? Tout conseil serait apprécié.

40
Nucleon

Une chose à laquelle j'ai pensé qui pourrait vous aider est que vous pouvez créer votre propre ServeMux. J'ai ajouté à votre exemple pour que chttp soit un ServeMux que vous puissiez avoir pour servir des fichiers statiques. Le HomeHandler vérifie ensuite s'il doit servir un fichier ou non. Je vérifie juste un "." mais vous pourriez faire beaucoup de choses. Juste une idée, ce n'est peut-être pas ce que vous cherchez.

package main

import (
    "fmt"
    "net/http"
    "strings"
)   

var chttp = http.NewServeMux()

func main() {

    chttp.Handle("/", http.FileServer(http.Dir("./")))

    http.HandleFunc("/", HomeHandler) // homepage
    http.ListenAndServe(":8080", nil)
}   

func HomeHandler(w http.ResponseWriter, r *http.Request) {

    if (strings.Contains(r.URL.Path, ".")) {
        chttp.ServeHTTP(w, r)
    } else {
        fmt.Fprintf(w, "HomeHandler")
    }   
} 
25
masebase

Une solution alternative (n'utilisant pas ServeMux ) consiste à servir explicitement chaque fichier situé dans le répertoire racine. L'idée derrière est de garder le nombre de fichiers basés sur la racine très petit. sitemap.xml , favicon.ico , robots.txt sont en effet mandatés pour être servis hors de la racine:

package main

import (
    "fmt"
    "net/http"
)

func HomeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "HomeHandler")
}

func serveSingle(pattern string, filename string) {
    http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
        http.ServeFile(w, r, filename)
    })
}

func main() {
    http.HandleFunc("/", HomeHandler) // homepage

    // Mandatory root-based resources
    serveSingle("/sitemap.xml", "./sitemap.xml")
    serveSingle("/favicon.ico", "./favicon.ico")
    serveSingle("/robots.txt", "./robots.txt")

    // Normal resources
    http.Handle("/static", http.FileServer(http.Dir("./static/")))

    http.ListenAndServe(":8080", nil)
}

Veuillez déplacer toutes les autres ressources (CSS, JS, etc.) vers un sous-répertoire approprié, par ex. /static/.

39
Deleplace

Utilisation de package Gorilla mux :

r := mux.NewRouter()

//put your regular handlers here

//then comes root handler
r.HandleFunc("/", homePageHandler)
//if a path not found until now, e.g. "/image/tiny.png" 
//this will look at "./public/image/tiny.png" at filesystem
r.PathPrefix("/").Handler(http.FileServer(http.Dir("./public/")))

http.Handle("/", r)
http.ListenAndServe(":8080", nil)
19
fatihpense