Подтвердить что ты не робот

Подавать домашнюю страницу и статический контент от root

В Golang, как мне выполнить статический контент из корневого каталога, все еще имея обработчик корневого каталога для обслуживания домашней страницы.

В качестве примера используйте следующий простой веб-сервер:

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")
}

Если я делаю

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

Я получаю панику, говоря, что у меня две регистрации для "/". Каждый пример Golang, который я нашел в Интернете, предлагает использовать их статический контент из разных каталогов, но это не очень помогает для таких вещей, как sitemap.xml, favicon.ico, robots.txt и другие файлы, которые являются практическими или обязанный всегда подаваться из корня.

Поведение, которое я ищу, - это поведение, которое встречается на большинстве веб-серверов, таких как Apache, Nginx или IIS, где оно сначала проходит ваши правила, и если не найдено ни одного правила, он ищет фактический файл, а если нет файла найдено 404s. Я предполагаю, что вместо написания http.HandlerFunc мне нужно написать http.Handler, который проверяет, ссылаюсь ли я на файл с расширением, и если это проверяет существование файла и обслуживает файл, в противном случае это 404s или обслуживает домашняя страница - запрос для "/". К сожалению, я не уверен, как начать такую ​​задачу.

Часть меня говорит, что я значительно усложняю ситуацию, которая заставляет меня думать, что я чего-то не хватает? Любые рекомендации будут оценены.

4b9b3361

Ответ 1

Одна вещь, о которой я подумал, может помочь вам в том, что вы можете создать свой собственный ServeMux. Я добавил к вашему примеру так, что chttp является ServeMux, что вы можете обслуживать статические файлы. Затем HomeHandler проверяет, должен ли он служить файлу или нет. Я просто проверяю ".". но вы могли бы многое сделать. Просто идея, возможно, не то, что вы ищете.

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")
    }   
} 

Ответ 2

Альтернативой (не используя ServeMux) является предоставление явно каждого файла, расположенного в корневом каталоге. Идея заключается в том, чтобы сохранить количество корневых файлов очень маленьким. sitemap.xml, favicon.ico, robots.txt действительно должны быть поданы из корня:

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)
}

Переместите все остальные ресурсы (CSS, JS и т.д.) в соответствующий подкаталог, например. /static/.

Ответ 3

Использование пакета мультии Gorilla:

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)