美文网首页
go restful源码剖析-2

go restful源码剖析-2

作者: tcuze | 来源:发表于2018-08-30 14:55 被阅读0次

    综述


    调试样例为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

          本文链接:https://www.haomeiwen.com/subject/kuzrwftx.html