使用gorilla/mux增强Go HTTP服务器的路由能力

栏目: IT技术 · 发布时间: 4年前

内容简介:今天这篇文章我们将会为我们之前编写的我们在之前写的

使用gorilla/mux增强Go HTTP服务器的路由能力

今天这篇文章我们将会为我们之前编写的 HTTP 服务器加上复杂路由的功能以及对路由进行分组管理。在之前的文章《 深入学习用 Go 编写HTTP服务器 》中详细地讲了使用 net/http 进行路由注册、监听网络连接、处理请求、安全关停服务的实现方法,使用起来非常方便。但是 net/http 有一点做的不是非常好的是,它没有提供类似 URL 片段解析、路由参数绑定这样的复杂路由功能。好在在 Go 社区中有一个非常流行的 gorilla/mux 包,它提供了对复杂路由功能的支持。在今天这篇文章中我们将探究如何用 gorilla/mux 包来创建具有命名参数、 GET/POST 处理、分组前缀、限制访问域名的路由。

安装 gorilla/mux

我们在之前写的 HTTP 服务的代码根目录,使用go get命令从GitHub安装软件包,如下所示:

go get  github.com/gorilla/mux

在《 深入学习用 Go 编写HTTP服务器 》中我们介绍过路由注册、匹配和最后处理函数的调用都是由 ServeMux (服务复用器)来完成的,而且我们还自己定义了复用器用以替换默认的 DefaultServeMux 。同样的 gorilla/mux 包也是为我们提供了一个复用器。这个复用器拥有很多功能用以提升编写 Web 应用的效率,而且与标准的 http.ServeMux 兼容。

使用 gorilla/mux

创建路由器

可以像下面这样创建一个路由器

router := mux.NewRouter()

会返回一个 mux.Router 实例, mux.Router 将传入的请求与已注册路由列表进行匹配,并为与 URL 或其他条件匹配的路由调用处理程序。主要特点是:

  • 可以根据URL主机,路径,路径前缀, Header 头、查询值, HTTP 方法进行路由匹配,或是使用自定义匹配器。
  • URL主机,路径和查询值可以是带有可选正则表达式的变量。
  • 路由可以被用作子路由,只有父路由匹配后才会尝试匹配子路由。这对于定义路由组非常有用,路由组可以共享主机、路径前缀、或者其他常见的属性。
  • 它实现了http.Handler接口,因此与标准的 http.ServeMux 完全兼容。

注册路由处理程序

我们将之前程序里自定义的服务复用器替换成上面创建好 mux.Router ,并为其注册路由处理器。

type helloHandler struct{}
func (*helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}
func WelcomeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Welcome!")
}

func main() {
    router := mux.NewRouter()
    router.Handle("/", &helloHandler{})
  router.HandleFunc("/welcome", WelcomeHandler)
  ......
}

之前我们是用 http.Hanlehttp.HandleFunc 注册处理程序的,这里直接换成 router.Hanlerouter.HanleFunc 即可,很方便。

定义带命名参数的路由

使用 mux.Router 的最大优势是可以从请求 URL 中提取分段,然后作为命名参数传入路由处理程序供使用。

接下来为我们的程序注册一个路由处理器,让服务器能够处理 URL/names/Gorge/countries/NewZealand 的请求:

router.HandleFunc("/names/{name}/countries/{country}", func(writer http.ResponseWriter, request *http.Request) {
            ......
})

接下来在处理函数中使用 mux.Vars() 函数从这些 URL 分段中获取数据。该函数以 http.Request 为参数并返回一个 URL 分段名为键,提取的数据为值的字典。

func(writer http.ResponseWriter, request *http.Request) {
        vars := mux.Vars(request)
        name := vars["name"]
        country := vars["country"]
        fmt.Fprintf(writer, "This guy named %s, was coming from %s .", name, country)
})

让服务器使用我们创建的路由器

这个设置很简单,如果没有自定义 http.Server 对象,使用 http.ListenAndServe(":8000", router) ,使用自己定义的`http.Server 对象时则是:

server := &http.Server{
    Addr:    ":8080",
    Handler: router,
}

这个和我们把自定义的服务复用器传递给 http.Server 没有任何区别。

改造完后我们之前写的 HTTP 服务器就可以根据具体的 URL 动态地构造响应。关键字回复 http02 可获得完整的源代码

其他 gorilla/mux 路由器的常用功能

设置路由的HTTP方法

限制路由处理器只处理指定的 HTTP 方法的请求:

router.HandleFunc("/books/{title}", CreateBook).Methods("POST")
router.HandleFunc("/books/{title}", ReadBook).Methods("GET")
router.HandleFunc("/books/{title}", UpdateBook).Methods("PUT")
router.HandleFunc("/books/{title}", DeleteBook).Methods("DELETE")

上面的就是一组可以响应具体 HTTP 方法的 RESTful 风格的接口的路由。

设置路由的域名

限制路由处理器只处理访问指定域名加路由的请求:

router.HandleFunc("/books/{title}", BookHandler).Host("www.mybookstore.com")

限制HTTP 方案

将请求处理程序可响应的 HTTP 方案限制为 http 或者 https

router.HandleFunc("/secure", SecureHandler).Schemes("https")
router.HandleFunc("/insecure", InsecureHandler).Schemes("http")

设置路径前缀和子路由

bookrouter := router.PathPrefix("/books").Subrouter()
bookrouter.HandleFunc("/", AllBooks)
bookrouter.HandleFunc("/{title}", GetBook)

使用 gorilla/mux 改进我们的 HTTP 服务器

接下来我们使用 gorilla/mux 对我们之前写的 HTTP 服务器做一下改进,之前我们所有程序都放在了 main.go 中,现在我们的程序还很小,所以我们先不把项目目录规划的太复杂,先通过文件做下简单的职责划分,新建两个文件 router.gohandler.go 分别用来存放路由注册的逻辑和路由对应的处理器函数,两个文件的示例内容如下。

handler.go :

package main

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

type HelloHandler struct{}

func (*HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World")
}

func ShowVisitorInfo(writer http.ResponseWriter, request *http.Request) {
    vars := mux.Vars(request)
    name := vars["name"]
    country := vars["country"]
    fmt.Fprintf(writer, "This guy named %s, was coming from %s .", name, country)
}

router.go :

package main

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

func RegisterRoutes(r *mux.Router) {
    indexRouter := r.PathPrefix("/index").Subrouter()
    indexRouter.Handle("/", &HelloHandler{})

    userRouter := r.PathPrefix("/user").Subrouter()
    userRouter.HandleFunc("/names/{name}/countries/{country}", ShowVisitorInfo)
}

router.go 中我们将路由分为 indexuser 两组,在两个路由组上分别定义路由。将这部分封装在一个导出函数 RegisterRoutes 供调用。这样即使以后路由注册的程序要放到单独的目录里也可以供外部调用。

整理完后我们的 main.go 中就会变的很简洁:

func main() {
   //mux := http.NewServeMux()
   //mux.Handle("/", &helloHandler{})
   muxRouter := mux.NewRouter()

   RegisterRoutes(muxRouter)

   server := &http.Server{
      Addr:    ":8080",
      Handler: muxRouter,
   }

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

关注公众号回复 go-http-02 获取本文中完整的示例代码。

前文回顾: 深入学习用 Go 编写HTTP服务器

喜欢我的文章,帮忙转发点赞,如在实践过程中遇到什么问题可在下方给我留言。

使用gorilla/mux增强Go HTTP服务器的路由能力


以上所述就是小编给大家介绍的《使用gorilla/mux增强Go HTTP服务器的路由能力》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

设计模式解析

设计模式解析

Alan Shalloway、James R.Trott / 徐言声 / 人民邮电出版社 / 2013-1 / 55.00元

《设计模式解析(第2版·修订版)》,本书首先概述了模式的基础知识,以及面向对象分析和设计在当代软件开发中的重要性,随后使用易懂的示例代码阐明了12个最常用的模式,使读者能够理解模式背后的基本原则和动机,理解为什么它们会这样运作。一起来看看 《设计模式解析》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具