脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - golang常用库之gorilla/mux-http路由库使用详解

golang常用库之gorilla/mux-http路由库使用详解

2021-01-26 01:01九卷 Golang

这篇文章主要介绍了golang常用库之gorilla/mux-http路由库使用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

一:golang自带路由介绍

golang自带路由库 http.ServerMux ,实际上是一个 map[string]Handler,是请求的url路径和该url路径对于的一个处理函数的映射关系。这个实现比较简单,有一些缺点:

不支持参数设定,例如/user/:uid 这种泛型类型匹配无法很友好的支持REST模式,无法限制访问方法(POST,GET等)也不支持正则

二:gorilla/mux路由

github地址:https://github.com/gorilla/mux
http://www.gorillatoolkit.org/pkg/mux
https://github.com/gorilla/mux#examples

上面所指出来的glang自带路由的缺点,gorilla/mux 都具备,而且还兼容 http.ServerMux。除了支持路径正则,命名路由,还支持中间件等等功能。所以mux是一个短小精悍,功能很全的路由。

1. 普通路由

示例 demo1.go

?
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
package main
 
import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)
 
func main() {
    r := mux.NewRouter()
    //普通路由
    r.HandleFunc("/", IndexHandler)
    r.HandleFunc("/products", ProductsHandler)
 
    http.ListenAndServe(":8080", r)
}
 
func IndexHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "hello world")
}
 
func ProductsHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "hello, Products")
}

上面mux的普通路由是不是似曾相识,跟golang标准库用法一样

在浏览器访问:http://localhost:8080/products
输出:hello, Products

2. 参数路由

参数路由,可以是普通路由,还可以是正则匹配
示例 demo2.go:

?
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
package main
 
import (
    "net/http"
 
    "fmt"
 
    "github.com/gorilla/mux"
)
 
//路由参数
func main() {
    r := mux.NewRouter()
    //1. 普通路由参数
    // r.HandleFunc("/articles/{title}", TitleHandler)
 
    //2. 正则路由参数,下面例子中限制为英文字母
    r.HandleFunc("/articles/{title:[a-z]+}", TitleHandler)
 
    http.ListenAndServe(":8080", r)
}
 
//https://github.com/gorilla/mux#examples
func TitleHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r) // 获取参数
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "title: %v\n", vars["title"])
}


第1个普通路由参数,就是啥参数都可以,不管是字母,数字,还是中文等
第2个正则路由参数,限制了只能是英文字母,否则会报 404 page not found

3. 路由匹配Matching Routes

https://github.com/gorilla/mux#matching-routes
我们也可以限制路由或者子路由。

3.1 匹配host

?
1
2
3
4
5
r := mux.NewRouter()
//只匹配 www.example.com
r.Host("www.example.com")
// 动态匹配子路由
r.Host("{subdomain:[a-z]+}.example.com")

 

3.2 更多的一些其他匹配

见下面的更多匹配的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
r := mux.NewRouter()
 
r.PathPrefix("/products/") //前缀匹配
r.Methods("GET", "POST") //请求方法匹配
r.Schemes("https") //schemes
r.Headers("X-Requested-With", "XMLHttpRequest") //header 匹配
r.Queries("key", "value") //query的值匹配
 
// 用户自定义方法 匹配
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
 return r.ProtoMajor == 0
})

把上面的联合起来在一个单独的route里

?
1
2
3
4
r.HandleFunc("/products", ProductsHandler).
 Host("www.example.com").
 Methods("GET").
 Schemes("http")

3.3 子路由匹配

Subrouter()可以设置子路由

?
1
2
3
4
5
6
r := mux.NewRouter()
s := r.Host("www.example.com").Subrouter()
 
s.HandleFunc("/products/", ProductsHandler)
s.HandleFunc("/products/{key}", ProductHandler)
s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)

3.4 多个路由匹配的顺序

如果有多个路由添加到路由器里面,那么匹配顺序是怎么样?按照添加的先后顺序匹配。比如有2个路由都匹配了,那么优先匹配第一个路由。

?
1
2
3
r := mux.NewRouter()
r.HandleFunc("/specific", specificHandler)
r.PathPrefix("/").Handler(catchAllHandler)

4. 设置路由前缀

PathPrefix()设置路由前缀

?
1
2
3
4
r := mux.NewRouter()
 
//PathPrefix() 可以设置路由前缀
product := r.PathPrefix("/products").HandleFunc("/", ProductsHandler)

路由前缀一般情况下不会单独使用,而是和子路由结合起来用,实现路由分组

5. 分组路由

可以根据前面的子路由和路由前缀的功能,综合运用就可以设置分组路由了
实例:grouprouter.go

?
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
package main
 
import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)
 
//子路由, 分组路由
func main() {
    r := mux.NewRouter()
 
    //PathPrefix() 可以设置路由前缀,设置路由前缀为products
    products := r.PathPrefix("/products").Subrouter()
    //"http://localhost:8080/products/", 最后面的斜线一定要,不然路由不正确,页面出现404
    products.HandleFunc("/", ProductsHandler)
    //"http://localhost:8080/products/{key}"
    products.HandleFunc("/{key}", ProductHandler)
 
    users := r.PathPrefix("/users").Subrouter()
    // "/users"
    users.HandleFunc("/", UsersHandler)
    // "/users/id/参数/name/参数"
    users.HandleFunc("/id/{id}/name/{name}", UserHandler)
 
    http.ListenAndServe(":8080", r)
}
 
func ProductsHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "%s", "products")
}
 
func ProductHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r) //获取路由的值
    fmt.Fprintf(w, "key: %s", vars["key"])
}
 
func UsersHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, " %s \r\n", "users handler")
}
 
func UserHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r) //获取值
    id := vars["id"]
    name := vars["name"]
    fmt.Fprintf(w, "id: %s, name: %s \r\n", id, name)
}

6. 路由中间件

https://github.com/gorilla/mux#middleware
Mux middlewares are defined using the de facto standard type: 在mux中路由中间件的定义

type MiddlewareFunc func(http.Handler) http.Handler

示例1:middleware1.go

?
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
package main
 
import (
    "fmt"
    "net/http"
 
    "github.com/gorilla/mux"
)
 
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", handler)
 
    r.Use(loggingMiddleware)
 
    http.ListenAndServe(":8080", r)
}
 
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //Do stuff here
        fmt.Println(r.RequestURI)
        fmt.Fprintf(w, "%s\r\n", r.URL)
        // Call the next handler, which can be another middleware in the chain, or the final handler.
        next.ServeHTTP(w, r)
    })
}
 
func handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("handle middleware"))
    fmt.Println("print handler")
}

 

示例2:middleware2.go

在来看一个复杂点的例子:

?
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
package main
 
import (
    "fmt"
    "net/http"
    "strings"
 
    "github.com/gorilla/mux"
)
 
type authMiddleware struct {
    tokenUsers map[string]string
}
 
func (amw *authMiddleware) Populate() {
    amw.tokenUsers = make(map[string]string)
    amw.tokenUsers["000"] = "user0"
    amw.tokenUsers["aaa"] = "userA"
    amw.tokenUsers["05ft"] = "randomUser"
    amw.tokenUsers["deadbeef"] = "user0"
}
 
func (amw *authMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := strings.Trim(r.Header.Get("X-Session-Token"), " ")
        if token == "" {
            fmt.Fprintf(w, "token is error \r\n")
        }
 
        if user, found := amw.tokenUsers[token]; found {
            //we found the token in out map
            fmt.Printf("Authenticated user: %s\n", user)
            fmt.Fprintf(w, "Authenticated user: %s\n", user)
            // Pass down the request to the next middleware (or final handler)
            next.ServeHTTP(w, r)
        } else {
            // Write an error and stop the handler chain
            http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}
 
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", handler)
 
    amw := authMiddleware{}
    amw.Populate()
 
    r.Use(amw.Middleware)
 
    http.ListenAndServe(":8080", r)
}
 
func handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("handler"))
}

用 insomnia 软件测试,如下图:

golang常用库之gorilla/mux-http路由库使用详解

X-Session-Token=aaa 返回时正确


那-Session-Token=aaaa 呢

golang常用库之gorilla/mux-http路由库使用详解

返回 403 了

7. Walking Routes 遍历注册的所有路由

?
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
package main
 
import (
    "fmt"
    "net/http"
    "strings"
 
    "github.com/gorilla/mux"
)
 
func handler(w http.ResponseWriter, r *http.Request) {
    return
}
 
//https://github.com/gorilla/mux#walking-routes
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", handler)
    r.HandleFunc("/products", handler).Methods("POST")
    r.HandleFunc("/articles", handler).Methods("GET")
    r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
    r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
    err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
        pathTemplate, err := route.GetPathTemplate()
        if err == nil {
            fmt.Println("ROUTE:", pathTemplate)
        }
        pathRegexp, err := route.GetPathRegexp()
        if err == nil {
            fmt.Println("Path regexp:", pathRegexp)
        }
        queriesTemplates, err := route.GetQueriesTemplates()
        if err == nil {
            fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
        }
        queriesRegexps, err := route.GetQueriesRegexp()
        if err == nil {
            fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
        }
        methods, err := route.GetMethods()
        if err == nil {
            fmt.Println("Methods:", strings.Join(methods, ","))
        }
        fmt.Println()
        return nil
    })
 
    if err != nil {
        fmt.Println(err)
    }
 
    http.Handle("/", r)
    http.ListenAndServe(":8080", nil)
}

8. 其他示例

请求方法限制

demo3.go:

?
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
package main
 
import (
    "fmt"
    "github.com/gorilla/mux"
    "net/http"
)
 
// 请求方法的限制, Methods()
func main() {
    r := mux.NewRouter()
 
    r.HandleFunc("/products", ProductsHandler).Methods("GET", "POST")
 
    r.Handle("/products/{id}", &ProductsIdHandler{}).Methods("GET")
    http.ListenAndServe(":8080", r)
}
 
func ProductsHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "hello, products! ")
}
 
type ProductsIdHandler struct{}
 
func (handler *ProductsIdHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "products id: %s", vars["id"])
}

请求头限制

在路由定义中可以通过Headers() 方法来限制设置请求头的匹配。
demo4.go

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
 
import (
    "fmt"
    "net/http"
 
    "github.com/gorilla/mux"
)
 
// 请求头的限制,用Headers() 来限制
func main() {
    r := mux.NewRouter()
 
    r.HandleFunc("/products", func(w http.ResponseWriter, r *http.Request) {
        header := "Request-Limit-Test"
        fmt.Fprintf(w, "contain headers: %s = %s \n", header, r.Header[header])
    }).Headers("Request-Limit-Test", "RequestLimitTest").Methods("POST")
 
    http.ListenAndServe(":8080", r)
}

自定义匹配规

用 MatcherFunc() 来自定义规则
示例 demo5.go:**

?
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
package main
 
import (
    "fmt"
    "net/http"
 
    "github.com/gorilla/mux"
)
 
//自定义匹配 MatcherFunc()
func main() {
    r := mux.NewRouter()
 
    r.HandleFunc("/products/matcher", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "FormValue: %s ", r.FormValue("func"))
    }).MatcherFunc(func(req *http.Request, match *mux.RouteMatch) bool {
        b := false
        if req.FormValue("func") == "matcherfunc" {
            b = true
        }
        return b
    })
 
    http.ListenAndServe(":8080", r)
}

在浏览器中:http://127.0.0.1:8080/products/matcher?func=matcherfunc
输出:FormValue: matcherfunc

命名路由Registered URLs

namerouter.go

?
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
package main
 
import (
    "fmt"
    "github.com/gorilla/mux"
    // "log"
    "net/http"
)
 
// 命名路由 Name(), 获取路由URL, URL()
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/products/{category}/{id:[0-9]+}", ProductHandler).Name("product")
 
    //获取路由的URL
    url1, err := r.Get("product").URL()
    fmt.Println(err) //error: mux: number of parameters must be multiple of 2, got [/]
    if err == nil {
        fmt.Println("get URL: \r\n", url1)
    }
 
    //获取路由的url后,也可以拼装你需要的URL
    url2, err := r.Get("product").URL("category", "tech", "id", "13")
    if err == nil {
        fmt.Println("new url: ", url2) //new url: /products/tech/13
    }
 
    http.ListenAndServe(":8080", r)
}
 
func ProductHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    vars := mux.Vars(r)
 
    fmt.Fprintf(w, "url: %s, category: %s, id: %s", r.URL, vars["category"], vars["id"])
    //浏览器: http://localhost:8080/products/id/23
 
    //output
    //url: /products/id/23, category: id, id: 23
}

根据命名的路由来获取路由URLr.Get("product").URL()

三:参考

https://github.com/gorilla/mux

到此这篇关于golang常用库之gorilla/mux-http路由库使用详解的文章就介绍到这了,更多相关gorilla mux-http路由库内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/jiujuan/p/12768907.html

延伸 · 阅读

精彩推荐
  • Golanggolang 通过ssh代理连接mysql的操作

    golang 通过ssh代理连接mysql的操作

    这篇文章主要介绍了golang 通过ssh代理连接mysql的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    a165861639710342021-03-08
  • Golanggo日志系统logrus显示文件和行号的操作

    go日志系统logrus显示文件和行号的操作

    这篇文章主要介绍了go日志系统logrus显示文件和行号的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    SmallQinYan12302021-02-02
  • GolangGolang中Bit数组的实现方式

    Golang中Bit数组的实现方式

    这篇文章主要介绍了Golang中Bit数组的实现方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    天易独尊11682021-06-09
  • Golanggolang如何使用struct的tag属性的详细介绍

    golang如何使用struct的tag属性的详细介绍

    这篇文章主要介绍了golang如何使用struct的tag属性的详细介绍,从例子说起,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看...

    Go语言中文网11352020-05-21
  • Golanggolang json.Marshal 特殊html字符被转义的解决方法

    golang json.Marshal 特殊html字符被转义的解决方法

    今天小编就为大家分享一篇golang json.Marshal 特殊html字符被转义的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    李浩的life12792020-05-27
  • GolangGolang通脉之数据类型详情

    Golang通脉之数据类型详情

    这篇文章主要介绍了Golang通脉之数据类型,在编程语言中标识符就是定义的具有某种意义的词,比如变量名、常量名、函数名等等,Go语言中标识符允许由...

    4272021-11-24
  • Golanggolang的httpserver优雅重启方法详解

    golang的httpserver优雅重启方法详解

    这篇文章主要给大家介绍了关于golang的httpserver优雅重启的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    helight2992020-05-14
  • Golanggo语言制作端口扫描器

    go语言制作端口扫描器

    本文给大家分享的是使用go语言编写的TCP端口扫描器,可以选择IP范围,扫描的端口,以及多线程,有需要的小伙伴可以参考下。 ...

    脚本之家3642020-04-25