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
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • restful hello world 首次浏览下go-restful的工程结构,从工程组织上面来看,工程包括两个...
    tcuze阅读 3,674评论 0 1
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,764评论 1 92
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,160评论 19 139
  • 前几天几个朋友一起吃饭,谈起一个话题:人生中最无助的是什么事? 勾起了我的回忆,一个人走进医院,挂号、排队,然后一...
    每日小情书阅读 1,814评论 0 1
  • 青春易逝,岁月无痕,在最美的年华选择安逸,谁辜负了谁? 十年寒窗,双亲劳累,在远行的时候选择归乡,谁辜负了谁? 志...
    哎呦那个谁阅读 2,571评论 0 0

友情链接更多精彩内容