golang常用庫(kù):gorilla/mux-http路由庫(kù)使用
golang常用庫(kù):配置文件解析庫(kù)-viper使用
golang常用庫(kù):操作數(shù)據(jù)庫(kù)的orm框架-gorm基本使用
一:golang自帶路由介紹
golang自帶路由庫(kù) http.ServerMux ,實(shí)際上是一個(gè) map[string]Handler,是請(qǐng)求的url路徑和該url路徑對(duì)于的一個(gè)處理函數(shù)的映射關(guān)系。這個(gè)實(shí)現(xiàn)比較簡(jiǎn)單,有一些缺點(diǎn):
不支持參數(shù)設(shè)定,例如/user/:uid 這種泛型類型匹配無(wú)法很友好的支持REST模式,無(wú)法限制訪問(wèn)方法(POST,GET等)也不支持正則
二:gorilla/mux路由
github地址:https://github.com/gorilla/mux
http://www.gorillatoolkit.org/pkg/mux
https://github.com/gorilla/mux#examples
上面所指出來(lái)的glang自帶路由的缺點(diǎn),gorilla/mux 都具備,而且還兼容 http.ServerMux。除了支持路徑正則,命名路由,還支持中間件等等功能。所以mux是一個(gè)短小精悍,功能很全的路由。
1. 普通路由
示例 demo1.go
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的普通路由是不是似曾相識(shí),跟golang標(biāo)準(zhǔn)庫(kù)用法一樣
在瀏覽器訪問(wèn):http://localhost:8080/products
輸出:hello, Products
2. 參數(shù)路由
參數(shù)路由,可以是普通路由,還可以是正則匹配
示例 demo2.go:
package main
import (
"net/http"
"fmt"
"github.com/gorilla/mux"
)
//路由參數(shù)
func main() {
r := mux.NewRouter()
//1. 普通路由參數(shù)
// r.HandleFunc("/articles/{title}", TitleHandler)
//2. 正則路由參數(shù),下面例子中限制為英文字母
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) // 獲取參數(shù)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "title: %v\n", vars["title"])
}
第1個(gè)普通路由參數(shù),就是啥參數(shù)都可以,不管是字母,數(shù)字,還是中文等
第2個(gè)正則路由參數(shù),限制了只能是英文字母,否則會(huì)報(bào) 404 page not found
3. 路由匹配Matching Routes
https://github.com/gorilla/mux#matching-routes
我們也可以限制路由或者子路由。
3.1 匹配host
r := mux.NewRouter()
//只匹配 www.example.com
r.Host("www.example.com")
// 動(dòng)態(tài)匹配子路由
r.Host("{subdomain:[a-z]+}.example.com")
3.2 更多的一些其他匹配
見(jiàn)下面的更多匹配的例子:
r := mux.NewRouter()
r.PathPrefix("/products/") //前綴匹配
r.Methods("GET", "POST") //請(qǐng)求方法匹配
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
})
把上面的聯(lián)合起來(lái)在一個(gè)單獨(dú)的route里
r.HandleFunc("/products", ProductsHandler).
Host("www.example.com").
Methods("GET").
Schemes("http")
3.3 子路由匹配
Subrouter()可以設(shè)置子路由
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 多個(gè)路由匹配的順序
如果有多個(gè)路由添加到路由器里面,那么匹配順序是怎么樣?按照添加的先后順序匹配。比如有2個(gè)路由都匹配了,那么優(yōu)先匹配第一個(gè)路由。
r := mux.NewRouter()
r.HandleFunc("/specific", specificHandler)
r.PathPrefix("/").Handler(catchAllHandler)
4. 設(shè)置路由前綴
PathPrefix()設(shè)置路由前綴
r := mux.NewRouter()
//PathPrefix() 可以設(shè)置路由前綴
product := r.PathPrefix("/products").HandleFunc("/", ProductsHandler)
路由前綴一般情況下不會(huì)單獨(dú)使用,而是和子路由結(jié)合起來(lái)用,實(shí)現(xiàn)路由分組
5. 分組路由
可以根據(jù)前面的子路由和路由前綴的功能,綜合運(yùn)用就可以設(shè)置分組路由了
實(shí)例:grouprouter.go
package main
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
)
//子路由, 分組路由
func main() {
r := mux.NewRouter()
//PathPrefix() 可以設(shè)置路由前綴,設(shè)置路由前綴為products
products := r.PathPrefix("/products").Subrouter()
//"http://localhost:8080/products/", 最后面的斜線一定要,不然路由不正確,頁(yè)面出現(xiàn)404
products.HandleFunc("/", ProductsHandler)
//"http://localhost:8080/products/{key}"
products.HandleFunc("/{key}", ProductHandler)
users := r.PathPrefix("/users").Subrouter()
// "/users"
users.HandleFunc("/", UsersHandler)
// "/users/id/參數(shù)/name/參數(shù)"
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
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
在來(lái)看一個(gè)復(fù)雜點(diǎn)的例子:
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 軟件測(cè)試,如下圖:
X-Session-Token=aaa 返回時(shí)正確
那-Session-Token=aaaa 呢
返回 403 了
7. Walking Routes 遍歷注冊(cè)的所有路由
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. 其他示例
請(qǐng)求方法限制
demo3.go:
package main
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
)
// 請(qǐng)求方法的限制, 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"])
}
請(qǐng)求頭限制
在路由定義中可以通過(guò)Headers() 方法來(lái)限制設(shè)置請(qǐng)求頭的匹配。
demo4.go
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
// 請(qǐng)求頭的限制,用Headers() 來(lái)限制
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)
}
自定義匹配規(guī)
用 MatcherFunc() 來(lái)自定義規(guī)則
示例 demo5.go:**
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
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
}
根據(jù)命名的路由來(lái)獲取路由URLr.Get("product").URL()
三:參考
https://github.com/gorilla/mux
到此這篇關(guān)于golang常用庫(kù)之gorilla/mux-http路由庫(kù)使用詳解的文章就介紹到這了,更多相關(guān)gorilla mux-http路由庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- 解決golang http重定向失效的問(wèn)題
- Golang發(fā)送http GET請(qǐng)求的示例代碼
- 詳解golang開(kāi)發(fā)中http請(qǐng)求redirect的問(wèn)題
- Golang Http 驗(yàn)證碼示例實(shí)現(xiàn)
- 詳解Golang開(kāi)啟http服務(wù)的三種方式
- 解決golang讀取http的body時(shí)遇到的坑