httprouter
httprouter 是一个高性能、可扩展的HTTP路由,上面我们列举的net/http
默认路由的不足,都被httprouter 实现,我们先用一个例子,认识下 httprouter 这个强大的 HTTP 路由。
安装:
1 |
go get -u github.com/julienschmidt/httprouter
|
在这个例子中,首先通过httprouter.New()
生成了一个*Router
路由指针,然后使用GET
方法注册一个适配/
路径的Index
函数,最后*Router
作为参数传给ListenAndServe
函数启动HTTP服务即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package main
import (
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Write([]byte( "Index" ))
}
func main() {
router := httprouter.New()
router.GET( "/" , Index)
log.Fatal(http.ListenAndServe( ":8080" , router))
}
|
httprouter 为所有的HTTP Method 提供了快捷的使用方式,只需要调用对应的方法即可。
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 |
func (r *Router) GET(path string, handle Handle) {
r.Handle( "GET" , path, handle)
}
func (r *Router) HEAD(path string, handle Handle) {
r.Handle( "HEAD" , path, handle)
}
func (r *Router) OPTIONS(path string, handle Handle) {
r.Handle( "OPTIONS" , path, handle)
}
func (r *Router) POST(path string, handle Handle) {
r.Handle( "POST" , path, handle)
}
func (r *Router) PUT(path string, handle Handle) {
r.Handle( "PUT" , path, handle)
}
func (r *Router) PATCH(path string, handle Handle) {
r.Handle( "PATCH" , path, handle)
}
func (r *Router) DELETE(path string, handle Handle) {
r.Handle( "DELETE" , path, handle)
}
|
现代的API,基本上都是Restful API,httprouter提供的命名参数的支持,可以很方便的帮助我们开发Restful API。比如我们设计的API/user/flysnow
,这这样一个URL,可以查看flysnow
这个用户的信息,如果要查看其他用户的,比如zhangsan
,我们只需要访问API/user/zhangsan
即可。
URL包括两种匹配模式:/user/:name精确匹配、/user/*name匹配所有的模式。
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 (
"github.com/julienschmidt/httprouter"
"net/http"
"log"
"fmt"
)
func main() {
router:=httprouter.New()
router.GET( "/MainData" , func (w http.ResponseWriter,r *http.Request,_ httprouter.Params) {
w.Write([]byte( "default get" ))
})
router.POST( "/MainData" , func (w http.ResponseWriter,r *http.Request,_ httprouter.Params) {
w.Write([]byte( "default post" ))
})
//精确匹配
router.GET( "/user/name" , func (w http.ResponseWriter,r *http.Request,p httprouter.Params) {
w.Write([]byte( "user name:" +p.ByName( "name" )))
})
//匹配所有
router.GET( "/employee/*name" , func (w http.ResponseWriter,r *http.Request,p httprouter.Params) {
w.Write([]byte( "employee name:" +p.ByName( "name" )))
})
http.ListenAndServe( ":8081" , router)
}
|
Handler处理链处理不同二级域名
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"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
type HostMap map [string]http.Handler
func (hs HostMap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println( "222" )
//根据域名获取对应的Handler路由,然后调用处理(分发机制)
if handler := hs[r.Host]; handler != nil {
handler.ServeHTTP(w, r)
} else {
http.Error(w, "Forbidden" , 403)
}
}
func main() {
userRouter := httprouter.New()
userRouter.GET( "/" , func (w http.ResponseWriter, r *http.Request, p httprouter.Params) {
w.Write([]byte( "play" ))
})
dataRouter := httprouter.New()
dataRouter.GET( "/" , func (w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
w.Write([]byte( "tool" ))
})
//分别用于处理不同的二级域名
hs := make(HostMap)
hs[ "user.localhost:12345" ] = userRouter
hs[ "data.localhost:12345" ] = dataRouter
log.Fatal(http.ListenAndServe( ":12345" , hs))
}
|
httprouter提供了很方便的静态文件服务,可以把一个目录托管在服务器上,以供访问。
1 |
router.ServeFiles( "/static/*filepath" ,http.Dir( "./" ))
|
使用ServeFiles
需要注意的是,第一个参数路径,必须要以/*filepath
,因为要获取我们要访问的路径信息。
1 2 3 4 5 6 7 8 9 10 11 12 |
func (r *Router) ServeFiles(path string, root http.FileSystem) {
if len(path) < 10 || path[len(path)-10:] != "/*filepath" {
panic( "path must end with /*filepath in path '" + path + "'" )
}
fileServer := http.FileServer(root)
r.GET(path, func (w http.ResponseWriter, req *http.Request, ps Params) {
req.URL.Path = ps.ByName( "filepath" )
fileServer.ServeHTTP(w, req)
})
}
|
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package main
import (
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
router := httprouter.New()
//访问静态文件
router.ServeFiles( "/static/*filepath" , http.Dir( "./files" ))
log.Fatal(http.ListenAndServe( ":8080" , router))
}
|
httprouter 异常捕获,httprouter允许使用者,设置PanicHandler
用于处理HTTP请求中发生的panic。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
panic( "error" )
}
func main() {
router := httprouter.New()
router.GET( "/" , Index)
//捕获异常
router.PanicHandler = func (w http.ResponseWriter, r *http.Request, v interface {}) {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "error:%s" , v)
}
log.Fatal(http.ListenAndServe( ":8080" , router))
}
|
httprouter还有不少有用的小功能,比如对404进行处理,我们通过设置Router.NotFound
来实现,我们看看Router
这个结构体的配置,可以发现更多有用的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
type Router struct {
//是否通过重定向,给路径自定加斜杠
RedirectTrailingSlash bool
//是否通过重定向,自动修复路径,比如双斜杠等自动修复为单斜杠
RedirectFixedPath bool
//是否检测当前请求的方法被允许
HandleMethodNotAllowed bool
//是否自定答复OPTION请求
HandleOPTIONS bool
//404默认处理
NotFound http.Handler
//不被允许的方法默认处理
MethodNotAllowed http.Handler
//异常统一处理
PanicHandler func (http.ResponseWriter, *http.Request, interface {})
}
|