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