【问题标题】:Second FileServer serves html but not images第二个 FileServer 提供 html 但不提供图像
【发布时间】:2020-06-30 18:49:59
【问题描述】:

在构建一个简单的 API 时,我在使用 Go 和 gorilla/mux 路由器时遇到了以下问题。我确定这是我脸上常见的愚蠢错误,但我看不到。

简化项目结构

|--main.go
|
|--public/--index.html
|        |--image.png
|
|--img/--img1.jpg
|     |--img2.jpg
|     |--...
|...

main.go

package main

import (
    "net/http"
    "github.com/gorilla/mux"
)

var Router = mux.NewRouter()

func InitRouter() {
    customers := Router.PathPrefix("/customers").Subrouter()

    customers.HandleFunc("/all", getAllCustomers).Methods("GET")
    customers.HandleFunc("/{customerId}", getCustomer).Methods("GET")
    // ...
    // Registering whatever middleware
    customers.Use(middlewareFunc)

    users := Router.PathPrefix("/users").Subrouter()

    users.HandleFunc("/register", registerUser).Methods("POST")
    users.HandleFunc("/login", loginUser).Methods("POST")
    // ...

    // Static files (customer pictures)
    var dir string
    flag.StringVar(&dir, "images", "./img/", "Directory to serve the images")
    Router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))

    var publicDir string
    flag.StringVar(&publicDir, "public", "./public/", "Directory to serve the homepage")
    Router.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(publicDir))))
}

func main() {
    InitRouter()
    // Other omitted configuration
    server := &http.Server{
        Handler: Router,
        Addr:    ":" + port,
        // Adding timeouts
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }

    err := server.ListenAndServe()
    // ...
}

子路由工作正常,中间件和所有。如果我转到localhost:5000/static/img1.pngimg 下的图像将正确提供。

问题是,去localhost:5000 服务于驻留在public 中的index.html,但随后localhost:5000/image.png404 not found

这里发生了什么?

【问题讨论】:

    标签: http go static mux


    【解决方案1】:

    改变这一行:

    // handles '/' and *ONLY* '/'
    Router.Handle("/",
            http.StripPrefix("/", http.FileServer(http.Dir(publicDir))))
    

    到这里:

    // handles '/' and all sub-routes
    Router.PathPrefix("/").Handler(
            http.StripPrefix("/",http.FileServer(http.Dir(publicPath))))
    

    基本上,在您的原始代码中,/ 的路由器正在处理此路径并且仅处理该路径(无子路由)。

    您可能想知道为什么您的原始代码至少对一个文件 (index.html) “有效”。原因是 http.FileServer 给定的路径是目录 - 而不是文件 - 将默认为索引页面文件 index.html 提供服务(请参阅 FileServer source)。

    使用PathPrefix 允许(文件服务器)处理程序接受路径/ 下方的所有 URL 路径。

    【讨论】:

    • 它有效,谢谢!还有一个问题。我假设我需要考虑我声明子路由器的顺序,就像 Go 的 net/http 一样,对吧?如果我在其他子路由器初始化之前将更正的语句向上移动,路由会混乱吗?
    • 我不使用 gorilla mux - 但看起来注册顺序很重要(第一次注册比赛获胜)。这不是 net/http 的情况,来自ServeMux docs 较长的模式优先于较短的模式,因此如果为“/images/”和“/images/thumbnails/”注册了处理程序,则后一个处理程序将针对以“/images/thumbnails/”开头的路径调用,而前者将接收对“/images/”子树中任何其他路径的请求。
    • 好的,谢谢!几周前我读过这件事,并在我的评论中错误地将其与声明顺序相关联。我站纠正!现在,如果我可以编辑上面的评论以避免混淆其他人......:/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 2015-04-11
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多