添加到container并注册到mux的是dispatch这个函数,它负责根据不同WebService的rootPath进行分发。
func (c *Container)addHandler(service *WebService, serveMux *http.ServeMux)bool {
pattern := fixedPrefixPath(service.RootPath())
serveMux.HandleFunc(pattern, c.dispatch)
}
webservice
每组webservice表示一个共享rootPath的服务,其中rootPath通过 ws.Path() 设置。
type WebService struct {
rootPath string
pathExpr *pathExpression
routes []Route
produces []string
consumes []string
pathParameters []*Parameter
filters []FilterFunction
documentation string
apiVersion string
typeNameHandleFunc TypeNameHandleFunction
dynamicRoutes bool
routesLock sync.RWMutex
}
通过Route注册的路由最终构成Route结构体,添加到WebService的routes中。
func (w *WebService)Route(builder *RouteBuilder)*WebService {
w.routesLock.Lock()
defer w.routesLock.Unlock()
builder.copyDefaults(w.produces, w.consumes)
w.routes = append(w.routes, builder.Build())
return w
}
route
通过RouteBuilder构造Route信息,Path结合了rootPath和subPath。Function是路由Handler,即处理函数,它通过 ws.Get(subPath).To(function) 的方式加入。Filters实现了个类似gRPC拦截器的东西,也类似go-chassis的chain。
type Route struct {
Method string
Produces []string
Consumes []string
Path string // webservice root path + described path
Function RouteFunction
Filters []FilterFunction
If []RouteSelectionConditionFunction
// cached values for dispatching
relativePath string
pathParts []string
pathExpr *pathExpression
// documentation
Doc string
Notes string
Operation string
ParameterDocs []*Parameter
ResponseErrors map[int]ResponseError
ReadSample, WriteSample interface{}
Metadata map[string]interface{}
Deprecated bool
}
dispatch
server侧的主要功能就是路由选择和分发。http包实现了一个 ServeMux ,go-restful在这个基础上封装了多个服务,如何在从container开始将路由分发给webservice,再由webservice分发给具体处理函数。这些都在 dispatch 中实现。
-
SelectRoute根据Req在注册的WebService中选择匹配的WebService和匹配的Route。其中路由选择器默认是 CurlyRouter 。
解析pathParams,将wrap的请求和相应交给路由的处理函数处理。如果有filters定义,则链式处理。
func (c *Container)dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
func() {
c.webServicesLock.RLock()
defer c.webServicesLock.RUnlock()
webService, route, err = c.router.SelectRoute(
c.webServices,
httpRequest)
}()
pathProcessor, routerProcessesPath := c.router.(PathProcessor)
pathParams := pathProcessor.ExtractParameters(route, webService, httpRequest.URL.Path)
wrappedRequest, wrappedResponse := route.wrapRequestResponse(writer,
httpRequest, pathParams)
if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 {
chain := FilterChain{Filters: allFilters, Target: func(req *Request, resp *Response) {
// handle request by route after passing all filters
route.Function(wrappedRequest, wrappedResponse)
}}
chain.ProcessFilter(wrappedRequest, wrappedResponse)
} else {
route.Function(wrappedRequest, wrappedResponse)
}
}









