五步用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 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!