• Golang【Web 入门】 08 集成 Gorilla Mux


    集成 Gorilla Mux

    我们将选用 gorilla/mux 来作为 goblog 的路由器。

    https://github.com/gorilla/mux

    为什么不选择 HttpRouter?

    HttpRouter
    https://github.com/julienschmidt/httprouter

    Gin
    https://github.com/gin-gonic/gin

    HttpRouter 是目前来讲速度最快的路由器,且被知名框架 Gin 所采用。

    不选择 HttpRouter 的原因是其功能略显单一,没有路由命名功能,不符合我们的要求。

    HttpRouter 和 Gin 比较适合在要求高性能,且路由功能要求相对简单的项目中,如 API 或微服务。在全栈的 Web 开发中,gorilla/mux 在性能上虽然有所不及,但是功能强大,比较实用。

    安装 gorilla/mux

    这是我们第一次安装第三方依赖,goblog 项目将使用官方推荐的 Go Module 来管理第三方依赖。

    Go Modules 相关知识下一节再来讲。本节专注于安装和使用 gorilla/mux。

    下面使用 go get 命令安装 gorilla/mux :

    go get -u github.com/gorilla/mux
    
    • 1

    安装成功后使用 git status 可以看到有两个文件变跟:

    输出:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    提示: 下一节,我们再来讲解这两个文件的作用。

    使用 gorilla/mux

    gorilla/mux 因实现了 net/http 包的 http.Handler 接口,故兼容 http.ServeMux ,也就是说,我们可以直接修改一行代码,即可将 gorilla/mux 集成到我们的项目中:

    main.go

    func main() {
        router := mux.NewRouter()
    }
    
    • 1
    • 2
    • 3

    注意: 修改以上代码后保存,因为安装了 Go for Visual Studio Code 插件,VSCode 会自动在文件顶部的 import 导入 mux 库,我们无需手动添加。

    依次以下链接:

    localhost:3000/
    localhost:3000/about
    localhost:3000/articles
    localhost:3000/no-exists
    localhost:3000/articles/2
    localhost:3000/articles/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以发现:

    123 可以正常访问。
    4 无法访问到自定义的 404 页面
    5 文章详情页无法访问
    6 可以访问到文章页面,但是 ID 为空
    
    • 1
    • 2
    • 3
    • 4

    这是因为 gorilla/mux 的路由解析采用的是 精准匹配 规则,而 net/http 包使用的是 长度优先匹配 规则。

    精准匹配 指路由只会匹配准确指定的规则,这个比较好理解,也是较常见的匹配方式。

    长度优先匹配 一般用在静态路由上(不支持动态元素如正则和 URL 路径参数),优先匹配字符数较多的规则。

    以我们的 goblog 为例:

    router.HandleFunc("/", defaultHandler)
    router.HandleFunc("/about", aboutHandler)
    
    • 1
    • 2

    使用 长度优先匹配 规则的 http.ServeMux 会把除了 /about 这个匹配的以外的所有 URI 都使用 defaultHandler 来处理。

    而使用 精准匹配 的 gorilla/mux 会把以上两个规则精准匹配到两个链接,/ 为首页,/about 为关于,除此之外都是 404 未找到。

    知道这个规则后,配合上面几个测试链接的返回结果,会更好理解。

    一般 长度优先匹配 规则用在静态内容处理上比较合适,动态内容,例如我们的 goblog 这种动态网站,使用 精准匹配 会比较方便。

    迁移到 Gorilla Mux

    基于以上规则,接下来改进代码:

    main.go

    package main
    
    import (
    	"fmt"
    	"net/http"
    
    	"github.com/gorilla/mux"
    )
    
    func homeHandler(w http.ResponseWriter, r *http.Request) {
    	w.Header().Set("Content-Type", "text/html; charset=utf-8")
    	fmt.Fprint(w, "

    Hello, 欢迎来到 goblog!

    "
    ) } func aboutHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, "此博客是用以记录编程笔记,如您有反馈或建议,请联系 "+ "1157818690@qq.com") } func notFoundHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusNotFound) fmt.Fprint(w, "

    请求页面未找到 :(

    如有疑惑,请联系我们。

    "
    ) } func articlesShowHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] fmt.Fprint(w, "文章 ID:"+id) } func articlesIndexHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "访问文章列表") } func articlesStoreHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "创建新的文章") } func main() { router := mux.NewRouter() router.HandleFunc("/", homeHandler).Methods("GET").Name("home") router.HandleFunc("/about", aboutHandler).Methods("GET").Name("about") router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandler).Methods("GET").Name("articles.show") router.HandleFunc("/articles", articlesIndexHandler).Methods("GET").Name("articles.index") router.HandleFunc("/articles", articlesStoreHandler).Methods("POST").Name("articles.store") // 自定义 404 页面 router.NotFoundHandler = http.HandlerFunc(notFoundHandler) // 通过命名路由获取 URL 示例 homeURL, _ := router.Get("home").URL() fmt.Println("homeURL: ", homeURL) articleURL, _ := router.Get("articles.show").URL("id", "23") fmt.Println("articleURL: ", articleURL) http.ListenAndServe(":3000", router) }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    接下来我们一步步分解代码。

    1. 新增 homeHandler

    首先,因为使用的是精确匹配,我们将 defaultHandler 变更 homeHandler 且将处理 404 的代码移除。

    2. 指定 Methods () 来区分请求方法

    看下这两个路由:

    router.HandleFunc("/articles", articlesIndexHandler).Methods("GET").Name("articles.index")
    router.HandleFunc("/articles", articlesStoreHandler).Methods("POST").Name("articles.store")
    
    • 1
    • 2

    命令行:

    E:\golang\src>curl http://127.0.0.1:3000/articles
    访问文章列表
    E:\golang\src>curl -X POST http://127.0.0.1:3000/articles
    创建新的文章
    E:\golang\src>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    解析正确。

    注意: 在 Gorilla Mux 中,如未指定请求方法,默认会匹配所有方法。

    3. 请求路径参数和正则匹配

    我们的文章详情页面的匹配:

    router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandler).Methods("GET").Name("articles.show")
    
    • 1

    注意 ID 路径的设置:

    {id:[0-9]+}
    
    • 1

    有以下规则:

    • 使用 {name} 花括号来设置路径参数。
    • 在有正则匹配的情况下,使用 : 区分。第一部分是名称,第二部分是正则表达式。
    [0-9]+
    
    • 1

    限定了 一个或者多个的数字。如果你访问非数字的 ID ,如 localhost:3000/articles/string 即会看到 404 页面。

    再看下在 Handler 里面我们如何获取到这个参数:

    func articlesShowHandler(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        id := vars["id"]
        fmt.Fprint(w, "文章 ID:"+id)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Mux 提供的方法 mux.Vars® 会将 URL 路径参数解析为键值对应的 Map,使用以下方法即可读取:

    vars["id"]
    
    • 1

    4. 命名路由与链接生成

    router.HandleFunc("/", homeHandler).Methods("GET").Name("home")
    router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandler).Methods("GET").Name("articles.show")
    
    • 1
    • 2

    Name() 方法用来给路由命名,传参是路由的名称,接下来我们就可以靠这个名称来获取到 URI:

    homeURL, _ := router.Get("home").URL()
    fmt.Println("homeURL: ", homeURL)
    articleURL, _ := router.Get("articles.show").URL("id", "1")
    fmt.Println("articleURL: ", articleURL)
    
    • 1
    • 2
    • 3
    • 4

    命令行切到我们的 air 窗口,即可看到 fmt.Println 打印出来的内容:

    在这里插入图片描述

  • 相关阅读:
    社交媒体营销策略——如何病毒式传播:增加受众范围的9个技巧
    红队内网攻防渗透:内网渗透之内网对抗:隧道技术篇&防火墙组策略&FRP&NPS&Chisel&Socks代理&端口映射&C2上线
    java八股文复习-----2024/03/04----基础
    3分钟告诉你如何成为一名黑客|零基础到黑客入门指南,你只需要掌握这五点能力
    计算机网络——网络安全
    rust - 理解borrow trait
    Redis---第一篇
    升级打怪课堂的题库更新了!
    时间序列预测 Graph-WaveNet:Graph WaveNet for Deep Spatial-Temporal Graph Modeling
    【AI视野·今日Robot 机器人论文速览 第四十六期】Tue, 3 Oct 2023
  • 原文地址:https://blog.csdn.net/weiguang102/article/details/128154353