gohttp/server/server.go

231 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package server
import (
"context"
"fmt"
"net/http"
"sort"
"strings"
"git.pyer.club/kingecg/gologger"
)
type RequestCtxKey string
type Route struct {
Method string
Path string
Handler http.Handler
matcher *UrlParamMatcher
middles *MiddlewareLink
}
func (route *Route) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if route.middles.Len() > 0 && !route.middles.ServeHTTP(w, r) {
return
}
route.Handler.ServeHTTP(w, r)
}
func (route *Route) Match(r *http.Request) bool {
l := gologger.GetLogger("Route")
l.Debug(fmt.Sprintf("match route: %s %s", r.Method, r.URL.Path))
if route.Method != "" && route.Method != r.Method {
l.Debug("method not match")
return false
}
if route.matcher != nil && route.matcher.Reg != 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
}
l.Debug("Not match matcher reg")
return false
}
if route.Path == "" {
return true
}
return strings.HasPrefix(r.URL.Path, route.Path)
}
func (route *Route) Add(m Middleware) {
route.middles.Add(m)
}
// NewRoute 返回一个新的Route实例
// 参数:
// - method: 请求方法
// - path: 请求路径
// - handleFn: http.Handler处理函数
// 返回值:
// - *Route: 一个指向Route的指针
func NewRoute(method string, path string, handleFn http.Handler) *Route {
ret := &Route{
Method: method,
Path: path,
middles: NewMiddlewareLink(),
}
p := ParseUrl(path)
// 使用handleFn构建handler
ret.Handler = handleFn
ret.matcher = &p
return ret
}
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 *MiddlewareLink
}
func (mux *RestMux) Use(m Middleware) {
mux.middlewares.Add(m)
}
func (mux *RestMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c := r.Context()
data := map[string]interface{}{}
cn := context.WithValue(c, RequestCtxKey("data"), data)
newRequest := r.WithContext(cn)
if mux.middlewares.Len() > 0 && !mux.middlewares.ServeHTTP(w, newRequest) {
return
}
// 根据r 从routes中找到匹配的路由
for _, route := range mux.routes {
if route.Match(newRequest) {
route.ServeHTTP(w, newRequest)
return
}
}
http.NotFound(w, r)
}
func (mux *RestMux) HandleFunc(method string, path string, f func(http.ResponseWriter, *http.Request)) *Route {
r := NewRoute(method, path, http.HandlerFunc(f))
mux.routes = append(mux.routes, r)
sort.Sort(mux.routes)
return r
}
func (mux *RestMux) Get(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("GET", path, f)
}
func (mux *RestMux) Post(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("POST", path, f)
}
func (mux *RestMux) Put(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("PUT", path, f)
}
func (mux *RestMux) Delete(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("DELETE", path, f)
}
func (mux *RestMux) Patch(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("PATCH", path, f)
}
func (mux *RestMux) Head(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("HEAD", path, f)
}
func (mux *RestMux) Option(path string, f func(http.ResponseWriter, *http.Request)) *Route {
return mux.HandleFunc("OPTION", path, f)
}
func (mux *RestMux) HandleMux(nmux *RestMux) *Route {
p := nmux.Path
if !strings.HasSuffix(p, "/") {
p = p + "/"
}
r := NewRoute("", p, nmux)
mux.routes = append(mux.routes, r)
sort.Sort(mux.routes)
return r
}
func NewRestMux(path string) *RestMux {
ret := &RestMux{
Path: path,
routes: Routes{},
middlewares: NewMiddlewareLink(),
}
return ret
}
type ServerMux struct {
http.Handler
directiveHandlers *MiddlewareLink
handlers map[string]http.Handler
paths []string
}
func (s *ServerMux) Handle(pattern string, handler http.Handler) {
if s.handlers == nil {
s.handlers = make(map[string]http.Handler)
}
s.handlers[pattern] = handler
s.paths = append(s.paths, pattern)
// 自定义比较函数排序s.paths
sort.Slice(s.paths, func(i, j int) bool {
return len(s.paths[i]) > len(s.paths[j]) || s.paths[i] > s.paths[j]
})
}
func (s *ServerMux) AddDirective(directiveStr string) {
//TODO: 根据字符串内容生成一个中间件链等directive实现再来补充逻辑
strs := strings.Split(directiveStr, " ")
directiveName := strs[0]
params := strs[1:]
directive, ok := DirectiveMap[directiveName]
if ok {
s.directiveHandlers.Add(directive(params...))
}
}
func (s *ServerMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, p := range s.paths {
if strings.HasPrefix(r.URL.Path, p) {
s.directiveHandlers.ServeHTTP(w, r)
s.handlers[p].ServeHTTP(w, r)
return
}
}
http.NotFound(w, r)
}