Golang中如何在同一路径上运行handlerFunc和文件服务器

Golang中如何在同一路径上运行handlerFunc和文件服务器 我有一个名为 requestHandler() 的函数,用于为 git 服务器实现 Smart-HTTP。当我在浏览器中访问该 URL 时,显示“未找到”。因此我考虑使用另一个处理程序添加文件服务器,虽然可以工作,但需要使用不同的 URL 路径。

http.Handle("/api/", http.StripPrefix("/api", requestHandler()))
http.Handle("/", http.FileServer(http.Dir(BasePath)))

但我希望两者能在同一个 URL/路径下工作。有没有办法实现这一点?


更多关于Golang中如何在同一路径上运行handlerFunc和文件服务器的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

想让他们都使用相同的URL/路径。有没有办法做到这一点?

你好 Vamsheeth。你应该使用 mux 来路由要处理的请求。

尝试使用像 gorilla mux 这样的多路复用器 Gorilla, the golang web toolkit

更多关于Golang中如何在同一路径上运行handlerFunc和文件服务器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你可以通过自定义 http.FileSystem 实现来在同一路径上同时处理 handlerFunc 和文件服务器。当请求的文件不存在时,回退到你的 requestHandler

以下是实现方案:

type hybridFileSystem struct {
    fs http.FileSystem
    handler http.Handler
}

func (h *hybridFileSystem) Open(name string) (http.File, error) {
    // 首先尝试从文件系统打开文件
    file, err := h.fs.Open(name)
    if err != nil {
        // 文件不存在,使用自定义handler处理请求
        return nil, err
    }
    
    // 检查是否是目录
    stat, err := file.Stat()
    if err != nil {
        file.Close()
        return nil, err
    }
    
    // 如果是目录,也交由自定义handler处理
    if stat.IsDir() {
        file.Close()
        return nil, os.ErrNotExist
    }
    
    return file, nil
}

// 自定义handler包装器
type fallbackHandler struct {
    fileServer http.Handler
    customHandler http.Handler
}

func (fh *fallbackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 创建响应写入器来捕获文件服务器的响应
    rw := &responseWriter{ResponseWriter: w, status: 200}
    
    // 尝试文件服务器
    fh.fileServer.ServeHTTP(rw, r)
    
    // 如果文件服务器返回404,使用自定义handler
    if rw.status == 404 {
        fh.customHandler.ServeHTTP(w, r)
    }
}

type responseWriter struct {
    http.ResponseWriter
    status int
}

func (rw *responseWriter) WriteHeader(code int) {
    rw.status = code
    rw.ResponseWriter.WriteHeader(code)
}

// 使用示例
func main() {
    basePath := "./static"
    
    hybridFS := &hybridFileSystem{
        fs: http.Dir(basePath),
        handler: requestHandler(),
    }
    
    fallback := &fallbackHandler{
        fileServer: http.FileServer(hybridFS),
        customHandler: requestHandler(),
    }
    
    http.Handle("/", fallback)
    http.ListenAndServe(":8080", nil)
}

另一种更简洁的方法是使用 http.HandlerFunc 包装器:

func hybridHandler(basePath string) http.Handler {
    fileServer := http.FileServer(http.Dir(basePath))
    customHandler := requestHandler()
    
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 首先检查请求的文件是否存在
        filePath := path.Join(basePath, r.URL.Path)
        if _, err := os.Stat(filePath); err == nil {
            // 文件存在,使用文件服务器
            fileServer.ServeHTTP(w, r)
        } else {
            // 文件不存在,使用自定义handler
            customHandler.ServeHTTP(w, r)
        }
    })
}

// 使用方式
func main() {
    http.Handle("/", hybridHandler("./static"))
    http.ListenAndServe(":8080", nil)
}

对于你的 Git Smart-HTTP 场景,这个方案允许:

  • 当请求静态文件(如 Git 对象文件)时由文件服务器处理
  • 当文件不存在时由你的 requestHandler 处理 Git 协议请求
  • 两者共享同一 URL 路径空间
回到顶部