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é.
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")
}
}
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/
.
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)