五步用golang封装自己web框架httper:第二步,实现阻断根路由和路由组
golang内置库http的ServeMux的根路由可以匹配所有路由,为此我们要阻断跟路由,同时根据路由前缀拼接实现路由组
添加breakRootRouterHandler方法,相当于一个中间件,用于阻断匹配了根路由方法但请求路径不是根路径的请求
http.go
func (sm *serveMux) Start(addr string) error {
var handler http.Handler
handler = sm.mux
if sm.IsBreakRootRouter {
handler = sm.breakRootRouterHandler(sm.mux)
}
return http.ListenAndServe(addr, handler)
}
func (sm *serveMux) breakRootRouterHandler(mux *http.ServeMux) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, pattern := mux.Handler(r)
rootRouter := fmt.Sprintf("%s %s", r.Method, "/")
// break root pattern
if pattern == rootRouter && r.URL.Path != "/" {
sm.NotFoundHandler.ServeHTTP(w, r)
return
}
mux.ServeHTTP(w, r)
})
}
使用Group方法新建serveMux实例,内置groupPrefix路由前缀进行路由分组
http.go
type serveMux struct {
mux *http.ServeMux
IsBreakRootRouter bool
NotFoundHandler http.Handler
// group
routers map[string]string
groupPrefix string
}
func New() *serveMux {
return &serveMux{
mux: http.NewServeMux(),
IsBreakRootRouter: true,
NotFoundHandler: http.NotFoundHandler(),
// group
routers: make(map[string]string),
}
}
func (sm *serveMux) Group(prefix string) *serveMux {
newServeMux := &serveMux{
mux: sm.mux,
IsBreakRootRouter: sm.IsBreakRootRouter,
NotFoundHandler: sm.NotFoundHandler,
routers: sm.routers,
groupPrefix: sm.groupPrefix+prefix,
}
return newServeMux
}
func (sm *serveMux) registerRouter(method string, router string, handler http.Handler) {
router = fmt.Sprintf("%s %s%s", method, sm.groupPrefix, router)
sm.routers[router] = funcName(handler)
sm.mux.Handle(router, handler)
}
func funcName(fn any) string {
n := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
return n
}
测试
http_test.go
package httper_test
import (
"fmt"
"github.com/golangpoke/httper"
"net/http"
"testing"
)
func TestServeMux_Run(t *testing.T) {
mux := httper.New()
mux.POST("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := w.Write([]byte(fmt.Sprintf("url: %s", r.URL.Path)))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}))
mux.POST("/api/v1/{value}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
value := r.PathValue("value")
if value == "" {
http.Error(w, "value is empty", http.StatusBadRequest)
return
}
_, err := w.Write([]byte(fmt.Sprintf("path value: %s", value)))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}))
t.Fatal(mux.Start(":8000"))
}
测试结果
POST 127.0.0.1:8000/
200 url:/
POST 127.0.0.1:8000/api
404 page not found
POST 127.0.0.1:8000/api
200 path value: test
本作品采用《CC 协议》,转载必须注明作者和本文链接