go restful源码剖析-2

综述


调试样例为examples\restful-no-cache-filter.go,在该例子主要是对hello world样例的扩展,主要在hello world中添加Filter,用来消除http访问的cache,代码如下。

func main() {
    ws := new(restful.WebService)
    ws.Filter(restful.NoBrowserCacheFilter)
    ws.Route(ws.GET("/hello").To(hello))
    restful.Add(ws)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func hello(req *restful.Request, resp *restful.Response) {
    io.WriteString(resp, "world")
}

Filter添加流程


ws.Filter(restful.NoBrowserCacheFilter)从字面意思上理解就是讲一个NoBrowserCacheFilter对象添加到filter中,NoBrowserCacheFilter是定义的FilterFunction函数。

// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction
type FilterFunction func(*Request, *Response, *FilterChain)

// NoBrowserCacheFilter is a filter function to set HTTP headers that disable browser caching
// See examples/restful-no-cache-filter.go for usage
func NoBrowserCacheFilter(req *Request, resp *Response, chain *FilterChain) {
    resp.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
    resp.Header().Set("Pragma", "no-cache")                                   // HTTP 1.0.
    resp.Header().Set("Expires", "0")                                         // Proxies.
    chain.ProcessFilter(req, resp)
}

在ws结构体中存有记录Filter相关数据的字段,对应的添加接口为,并将FilterFunction:NoBrowserCacheFilter添加到type WebService struct { filters []FilterFunction }中进行维护,ws的启动流程同example/hello-world.go的流程相同。

func (w *WebService) Filter(filter FilterFunction) *WebService {
    w.filters = append(w.filters, filter)
    return w
}

Filter函数的执行


在http请求访问时,restful调用dispatch进行req的分发,在完成route select之后,执行绑定的hello函数前,需要对用户定的的Filter进行先行判定, 并将用户定义的Filter全部统计到allFilters中,并初始化FilterChain,在restful中Filter的规则是可以被覆盖掉的,按照优先级container filter < webservices < route执行。

func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
    if len(c.containerFilters)+len(webService.filters)+len(route.Filters) > 0 {
        // compose filter chain
        allFilters := []FilterFunction{}
        allFilters = append(allFilters, c.containerFilters...)
        allFilters = append(allFilters, webService.filters...)
        allFilters = append(allFilters, route.Filters...)
        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 {// example hello world在这里执行执行绑定函数
        // no filters, handle request by route
        route.Function(wrappedRequest, wrappedResponse)
    }
}

Filter Chain中实际上是对Filter规则和目标function的进一步包装,之所以叫做chain是因为对fliter的执行是通过递归调用的方式,并有Index控制Filter的递归层数,代码如下:

// FilterChain is a request scoped object to process one or more filters before calling the target RouteFunction.
type FilterChain struct {
    Filters []FilterFunction // ordered list of FilterFunction
    Index   int              // index into filters that is currently in progress
    Target  RouteFunction    // function to call after passing all filters
}

其中Filter字段中记录了所有的Filter规则,Targe绑定了玩家定义的需要执行的函数, 后面通过调用定义在Filter中的ProcessFilter函数执行对应的Filters及user function: hello。

// ProcessFilter passes the request,response pair through the next of Filters.
// Each filter can decide to proceed to the next Filter or handle the Response itself.
func (f *FilterChain) ProcessFilter(request *Request, response *Response) {
    if f.Index < len(f.Filters) {
        f.Index++
        f.Filters[f.Index-1](request, response, f)
    } else {
        f.Target(request, response)
    }
}

用户自定义filter


既然restful提供了Filter的通用接口,并提供NoBrowserCacheFilter样例,那么用户也可以自定义响应的Filter接口,在该小结中,将仿照NoBrowserCacheFilter的实现方式在package main中自定义用户的Filter函数,改变用户访问resp的header中的字段,代码如下:


func main() {
    ws := new(restful.WebService)
    ws.Filter(restful.NoBrowserCacheFilter)
    // 将自定义Filter添加到ws Filter中
    ws.Filter(UserCustomFilter)
    ws.Route(ws.GET("/hello").To(hello))
    restful.Add(ws)
    log.Fatal(http.ListenAndServe(":8080", nil))
}
   
func UserCustomFilter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
    //创建新字段
    resp.Header().Set("custom", "test") // HTTP 1.1.
    //覆盖掉NoBrowserCacheFilter中的pargma字段
    resp.Header().Set("Pragma", "test") // HTTP 1.0.
    //递归调用下一个pross Filter,取名为chain的原因
    chain.ProcessFilter(req, resp)
}

http访问后返回的http header如下:其中用户自定义的Filter覆盖掉了NoBrowserCacheFilter中的pargma字段,并新添加custom字段。

cache-control → no-cache, no-store, must-revalidate
custom → test
date →Tue, 21 Aug 2018 08:40:14 GMT
expires → 0
pragma → test

你可能感兴趣的:(go restful源码剖析-2)