Go语言实现一个Http Server框架(四) 支持RestFul Api

102 阅读2分钟

到目前为止,服务是可以正常运行了,但是,我们并没有对接口的访问做方法限制。因为之前的代码我们是照抄go的原生http库,无法满足我们的预期,所以,我们需要对代码进行一定的修改

修改Route方法

首先我们需要在Route方法中添加method参数,用来接收请求方法

type Srever interface{
    Route(method string, pattern string, handleFunc func(ctx *Context))
    Start(address string) error
}

在对应的方法接收器中也要添加对应的参数

func (s *sdkHttpServer) Route(method string, pattern string, handleFunc func(ctx *Context)) {  
     http.HandleFunc(pattern,func(writer http.ResponseWriter,request *http.Request)){
         ctx := NewContext(writer,request)
         handleFunc(ctx)
     }
  
}

但是http.HandleFunc没有method参数,我们可以考虑用下面的方式来实现

func (s *sdkHttpServer) Route(method string, pattern string, handleFunc func(ctx *Context)) {  
     http.HandleFunc(pattern,func(writer http.ResponseWriter,request *http.Request)){
         if request.Method != method{
             writer.Write([]byte("error method"))
         }
         ctx := NewContext(writer,request)
         handleFunc(ctx)
     }
  
}

这样写虽然可行,但看上去总是不太舒服,所以我们换一条思路

改用http.Handler进行实现

在http库中,有一个Handle方法(http/server.go)

image.png 这个方法接收两个参数,string类型的pattern和一个Handler接口

image.png 首先,我们实现Handler接口

type HandlerBasedOnMap struct{
    // key  method+url  用于区别请求方法
    handlers map[string]func(ctx *Context)
}


func (h *HandlerBasedOnMap) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
    
}

然后实现实现key的逻辑

func (h *HandlerBasedOnMap) key(req *http.Request) string{
    return req.Mothed + "#" + req.URL.Path
}

重写Haddler接口里的ServeHTTP方法,实现请求方法处理逻辑

func (h *HandlerBasedOnMap) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
    key := h.key(request)
    if h.handler,ok:=h.handlers[key],ok{
        handler(NewContext(writer,request))
    }else{
        writer.WriteHeader(statusCode:http.StatusNotFound)
        writer.Write([]byte("Not Found"))
    }
}

修改Route方法

func (s *sdkHttpServer) Route(method string, pattern string, handleFunc func(ctx *Context)) {   
    http.Handle("/",&HandlerBasedOnMap{})  
}

不过因为我们只需要注册一次,所以我们将代码移动到Start方法,并且让Server持有Handler

type sdkHttpServer struct {  
    Name string  
    handler *HandlerBasedOnMap{}  
}

// Start 启动服务  
func (s *sdkHttpServer) Start(address string) error {  
    http.Handle("/",s.handler)   
    return http.ListenAndServe(address, nil)  
}

而Route方法则做出下面的修改

func (s *sdkHttpServer) Route(method string, pattern string, handleFunc func(ctx *Context)) {  
    //加入请求方法限制  
    key := s.handler.key(method, pattern)
    //TODO:处理重复注册
    s.handler.handlers[key] = handleFunc    
}

此时,我们已经可以支持对方法的限制,但是仍然存在一些问题

  1. Route方法的实现依赖于HandlerBasedOnMap的内部细节,和HandlerBaseOnMap强耦合
  2. 如果后期考虑路由树的扩展,sdkHttpServer也需要修改 后面我们需要针对这些问题做出调整