Golang中除了Gorilla/Mux之外还有哪些好用的路由库推荐?

Golang中除了Gorilla/Mux之外还有哪些好用的路由库推荐? 我想学习Go语言中的路由(不使用第三方库),我相信我应该学会用Go语言自己实现,而且我尽可能不想依赖第三方库。不是说gorilla/mux不好,但我真的不喜欢使用第三方库,除非别无选择(比如OpenGL、OpenSSL)。

8 回复

那么,net/http 就是你的工具。具体来说,使用 ServeMux 进行路由:https://golang.org/pkg/net/http/#ServeMux

更多关于Golang中除了Gorilla/Mux之外还有哪些好用的路由库推荐?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你见过 https://github.com/quii/learn-go-with-tests 吗?

特别是 HTTP 服务器与 JSON、路由和嵌入部分。这些章节展示了如何使用 net/http 开始构建一个简单的服务器。解析 request.URL.Path 获取变量、方法匹配等等…

我相信作者后续会切换到 gorilla/mux。这个过程可能会很有意思。

作为对比观点,我使用纯 net/http 开发过许多网络服务。Gorilla 路由库确实有其适用场景,当你需要在端点路径中处理大量占位符时会发现它很有用。但从 net/http 开始完全合理,直到你因某些原因觉得使用原生库过于繁琐时,这时你就具备了良好的基础来决策是否切换到更复杂的方案。

嗯,避免使用像 gorilla/mux 这样的路由器并不是一个好主意。该项目非常成熟且维护良好,已在数百个项目中使用。当然,你可以从头开始编写所有代码,但实现所有那些匹配、中间件等功能可能需要很长的过程。

如果你担心意外情况(比如不兼容性,或者更糟的……项目被放弃),你可以使用 vendor 文件夹下载、使用并重新分发(请查看许可证)一个固定版本的 mux 与你的项目一起使用。

@geosoft1 说得很有道理——这主要取决于个人偏好和您关注的重点。如果减少代码行数很重要,那么 Gorilla:mux 是不错的选择。如果降低耦合度和提高灵活性更重要,那么在处理程序中实现路由是个好方法。

在处理程序中实现路由的另一个好处是,它帮助您以清晰的层次结构组织路由,因为您不能随意添加路径——所有路径都需要以逻辑方式贯穿。

我还没有使用这种方法实现身份验证等功能,所以对我来说这仍处于实验阶段。但是,身份验证通常通过用中间件包装处理程序来实现,因此我不确定这两种方法在这方面会有显著差异。

我喜欢这种方法:

https://blog.merovius.de/2017/06/18/how-not-to-use-an-http-router.html

另一个示例请参见:

package api

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/simpleiot/simpleiot/assets/frontend"
	"github.com/simpleiot/simpleiot/db"
)

// IndexHandler is used to serve the index page
type IndexHandler struct{}

func (h *IndexHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	fmt.Println("indexHandler")
	f := frontend.Asset("/index.html")

此文件已被截断。显示完整内容

让我暂时扮演魔鬼代言人,为了建设性的讨论 😊

我同意在小项目、学习场景或独立服务中使用标准库。但对于其他情况,使用路由器(这里我们讨论的是 gorilla)确实能带来便利,特别是 gorilla 让代码变得非常清晰易读。

之前文章中提到的技术方法虽然从技术角度看很有趣,但我认为从项目管理角度来说并不实用。 例如作者认为框架会带来大量代码,而且难以调试。考虑到可执行文件的大小,增加的代码量其实是很合理的。关于调试,你是在处理器层面进行调试,而不是在路由器层面,我不太明白你期望在路由器中调试什么?

另一个问题是像这个或文章中那个代码的复杂性。我看到这些代码不够清晰,难以阅读和理解,可能也难以扩展,这对于严肃的项目来说并不理想,而且也不符合 Go 语言的简洁范式。添加认证或切换方法可能会导致完全混乱……我建议看看这个小例子来理解我的意思。

在Go语言中,标准库net/http提供了内置的路由功能,无需依赖第三方库如Gorilla/Mux。你可以使用http.ServeMux或自定义路由逻辑来实现。下面我将详细说明如何利用标准库构建路由,并给出示例代码。

使用标准库net/http的路由实现

Go的net/http包包含ServeMux类型,它是一个HTTP请求多路复用器(即路由),允许你注册处理器函数到特定路径。此外,你可以通过自定义逻辑扩展路由功能,例如路径参数解析或中间件支持。

示例1:基本路由使用http.ServeMux

这个示例展示了如何使用http.ServeMux注册简单的路由,并启动HTTP服务器。

package main

import (
    "fmt"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    
    // 注册路由处理器
    mux.HandleFunc("/", homeHandler)
    mux.HandleFunc("/about", aboutHandler)
    mux.HandleFunc("/user/", userHandler) // 注意:以斜杠结尾,匹配以/user/开头的路径
    
    // 启动服务器
    fmt.Println("服务器运行在 http://localhost:8080")
    http.ListenAndServe(":8080", mux)
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.NotFound(w, r)
        return
    }
    fmt.Fprintf(w, "欢迎访问首页!")
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "这是关于页面。")
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    // 简单解析路径:例如 /user/123 提取ID
    path := r.URL.Path
    if len(path) > len("/user/") {
        userID := path[len("/user/"):]
        fmt.Fprintf(w, "用户ID: %s", userID)
    } else {
        http.NotFound(w, r)
    }
}

在这个例子中:

  • 我们创建了一个新的ServeMux实例。
  • 使用HandleFunc方法注册了根路径//about和以/user/开头的路径的处理器函数。
  • 对于/user/路径,我们手动解析路径参数(如用户ID),而不依赖第三方库。
  • 服务器监听8080端口,处理传入的HTTP请求。

示例2:自定义路由逻辑实现路径参数和中间件

如果需要更高级的功能,如路径参数提取或中间件,你可以通过自定义处理器函数实现。以下示例演示了如何解析路径参数(例如RESTful风格的/users/{id})并添加简单的日志中间件。

package main

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

// 自定义路由结构,用于存储路由映射
type Router struct {
    routes map[string]http.HandlerFunc
}

func NewRouter() *Router {
    return &Router{
        routes: make(map[string]http.HandlerFunc),
    }
}

// 添加路由:支持简单路径匹配,这里使用精确匹配,但可以扩展为通配符
func (r *Router) AddRoute(path string, handler http.HandlerFunc) {
    r.routes[path] = handler
}

// 实现http.Handler接口,处理请求
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    path := req.URL.Path
    
    // 检查精确匹配的路由
    if handler, exists := r.routes[path]; exists {
        // 调用中间件包装的处理器(这里添加简单日志)
        logMiddleware(handler).ServeHTTP(w, req)
        return
    }
    
    // 处理动态路径,例如 /users/123
    if strings.HasPrefix(path, "/users/") {
        userID := strings.TrimPrefix(path, "/users/")
        if userID != "" {
            // 调用用户详情处理器,传递用户ID
            userDetailHandler(w, req, userID)
            return
        }
    }
    
    // 如果没有匹配的路由,返回404
    http.NotFound(w, req)
}

// 中间件:日志记录
func logMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        fmt.Printf("收到请求: %s %s\n", r.Method, r.URL.Path)
        next(w, r)
    }
}

// 处理器函数
func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "首页内容")
}

func aboutHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "关于我们")
}

func userDetailHandler(w http.ResponseWriter, r *http.Request, userID string) {
    fmt.Fprintf(w, "用户详情,ID: %s", userID)
}

func main() {
    router := NewRouter()
    router.AddRoute("/", homeHandler)
    router.AddRoute("/about", aboutHandler)
    
    fmt.Println("服务器运行在 http://localhost:8080")
    http.ListenAndServe(":8080", router)
}

在这个例子中:

  • 我们定义了一个自定义Router结构,使用映射来存储路由和处理器函数。
  • ServeHTTP方法处理所有传入请求,检查路径匹配,并支持动态路径解析(如/users/{id})。
  • 添加了logMiddleware作为中间件,用于记录请求日志,展示了如何扩展功能。
  • 这种方法避免了第三方依赖,同时提供了灵活的路由控制。

总结

通过Go标准库的net/http,你可以实现强大的路由功能,包括静态路径、动态路径参数和中间件。以上示例展示了从基础到高级的用法,帮助你构建不依赖第三方库的Web应用。如果你需要更复杂的特性(如正则表达式路由),可以进一步扩展自定义逻辑,而无需引入外部包。

回到顶部