package server import ( "context" "net/http" "sort" "strings" ) type RequestCtxKey string type Route struct { Method string Path string Handle http.HandlerFunc Handler http.Handler matcher *UrlParamMatcher } func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) { if route.Handler != nil { route.Handler.ServeHTTP(w, r) } else { route.Handle(w, r) } } func (route *Route) Match(r *http.Request) bool { if route.Method != "" && route.Method != r.Method { return false } if route.matcher != nil { params, matched := MatchUrlParam(r.URL.Path, route.matcher) if matched { ctx := r.Context() data := ctx.Value(RequestCtxKey("data")).(map[string]interface{}) for _, p := range route.matcher.Params { data[p] = params[p] } return true } return false } if route.Path == "" { return true } return strings.HasPrefix(r.URL.Path, route.Path) } type Routes []*Route func (rs Routes) Less(i, j int) bool { iPaths := strings.Split(rs[i].Path, "/") jPaths := strings.Split(rs[j].Path, "/") if len(iPaths) > len(jPaths) { return true } if len(iPaths) < len(jPaths) { return false } for k := 0; k < len(iPaths); k++ { if iPaths[k] != jPaths[k] { return iPaths[k] < jPaths[k] } } return false } func (rs Routes) Len() int { return len(rs) } func (rs Routes) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] } // 可以嵌套的Rest http server mux type RestMux struct { Path string routes Routes middlewares []Middleware } func (mux *RestMux) Use(m Middleware) { mux.middlewares = append(mux.middlewares, m) } func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { canContinue := false c := r.Context() data := map[string]interface{}{} cn := context.WithValue(c, RequestCtxKey("data"), data) newRequest := r.WithContext(cn) if len(mux.middlewares) > 0 { for _, m := range mux.middlewares { canContinue = false m(w, newRequest, func() { canContinue = true }) if !canContinue { return } } } // _, has := lo.Find(mux.rmuxPaths, func(s string) bool { // return strings.HasPrefix(newRequest.URL.Path, s) // }) // if has { // mux.imux.ServeHTTP(w, newRequest) // return // } // 根据r 从routes中找到匹配的路由 for _, route := range mux.routes { if route.Match(newRequest) { route.ServeHTTP(w, newRequest) return } } // newRequest.URL.Path = "/" + strings.ToLower(newRequest.Method) + newRequest.URL.Path // newRequest.RequestURI = "/" + strings.ToLower(newRequest.Method) + newRequest.RequestURI // h, _ := mux.imux.Handler(newRequest) // h.ServeHTTP(w, newRequest) http.NotFound(w, r) } func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) { r := &Route{ Method: method, Path: path, Handle: f, Handler: nil, } *r.matcher = ParseUrl(path) mux.routes = append(mux.routes, r) sort.Sort(mux.routes) } func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("GET", path, f) } func (mux *RestMux) Post(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("POST", path, f) } func (mux *RestMux) Put(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("PUT", path, f) } func (mux *RestMux) Delete(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("DELETE", path, f) } func (mux *RestMux) Patch(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("PATCH", path, f) } func (mux *RestMux) Head(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("HEAD", path, f) } func (mux *RestMux) Option(path string, f func(http.ResponseWriter, *http.Request)) { mux.HandleFunc("OPTION", path, f) } func (mux *RestMux) HandleMux(nmux *RestMux) { p := nmux.Path if !strings.HasSuffix(p, "/") { p = p + "/" } // mux.imux.Handle(p, http.StripPrefix(nmux.Path, nmux)) // mux.rmuxPaths = append(mux.rmuxPaths, nmux.Path) r := &Route{ Method: "", Path: p, Handle: nil, Handler: nmux, } r.matcher = &UrlParamMatcher{ Params: []string{}, Reg: nil, } sort.Sort(mux.routes) } func NewRestMux(path string) *RestMux { ret := &RestMux{ Path: path, routes: Routes{}, middlewares: []Middleware{}, } return ret }