输入输出中间件
输入输出中间件可以完全代替 Hprose 过滤器。使用输入输出中间件还是使用 Hprose 过滤器完全看开发者喜好。
输入输出中间件的形式为:
- func(
- request []byte,
- context Context,
- next NextFilterHandler) (response []byte, err error) {
- ...
- response, err = next(request, context)
- ...
- return response, err
request
是原始请求数据,对于客户端来说它是输出数据,对于服务器端来说,它是输入数据。
context
是调用上下文对象。
next
表示下一个中间件。通过调用 next
将各个中间件串联起来。
next
的返回值 response
是返回的响应数据。对于客户端来说,它是输入数据。对于服务器端来说,它是输出数据。
跟踪调试
下面我们来看一下 Hprose 过滤器中的跟踪调试的例子在这里如何实现。
- package main
- import (
- "fmt"
- "github.com/hprose/hprose-golang/rpc"
- )
- type logFilter struct {
- Prompt string
- }
- func (lf logFilter) handler(
- request []byte,
- context rpc.Context,
- next rpc.NextFilterHandler) (response []byte, err error) {
- fmt.Printf("%v: %s\r\n", lf.Prompt, request)
- response, err = next(request, context)
- fmt.Printf("%v: %s\r\n", lf.Prompt, response)
- return
- }
- func hello(name string) string {
- return "Hello " + name + "!"
- }
- type HelloService struct {
- Hello func(string) (string, error)
- }
- func main() {
- server := rpc.NewTCPServer("")
- server.AddFunction("hello", hello)
- server.AddBeforeFilterHandler(logFilter{"Server"}.handler)
- server.Handle()
- client := rpc.NewClient(server.URI())
- client.AddBeforeFilterHandler(logFilter{"Client"}.handler)
- var helloService *HelloService
- client.UseService(&helloService)
- helloService.Hello("World")
- client.Close()
- server.Close()
- }
执行结果为:
Client: Cs5"Hello"a1{s5"World"}z
Server: Cs5"Hello"a1{s5"World"}z
Server: Rs12"Hello World!"z
Client: Rs12"Hello World!"z
这个结果跟使用 Hprose 过滤器的例子的结果一样。
但是我们发现,这里使用 Hprose 中间件要写的代码比起 Hprose 过滤器更简单,只需要一个方法就可以了。
另外,因为这个例子中,我们没有使用过滤器功能,因此使用 AddBeforeFilterHandler
(或 BeforeFilter.Use
)方法或者 AddAfterFilterHandler(或 AfterFilter.Use
)方法添加中间件处理器效果都是一样的。
但如果我们使用了过滤器的话,那么 AddBeforeFilterHandler
添加的中间件处理器的 request
数据是未经过过滤器处理的。过滤器的处理操作在 next
的最后一环中执行。next
返回的响应 response
是经过过滤器处理的。
如果某个通过 AddBeforeFilterHandler
添加的中间件处理器跳过了 next
而直接返回了结果的话,则返回的 response
也是未经过过滤器处理的。而且如果某个 AddBeforeFilterHandler
添加的中间件处理器跳过了 next
,不但过滤器不会执行,而且在它之后使用 AddBeforeFilterHandler
所添加的中间件处理器也不会执行,AddAfterFilterHandler
方法所添加的所有中间件处理器也都不会执行。
而 AddAfterFilterHandler
添加的处理器所收到的 request
都是经过过滤器处理以后的,但它当中使用 next
方法返回的 response
是未经过过滤器处理的。
下面,我们在来看一个结合了压缩过滤器和输入输出缓存中间件的例子。
压缩、缓存、计时
压缩我们使用 Hprose 过滤器 一章中的 compress_handler.go,这里就不列代码了。
- package main
- import (
- "fmt"
- "time"
- "sync"
- "github.com/hprose/hprose-golang/rpc"
- )
- type cacheFilter struct {
- Cache map[string][]byte
- sync.RWMutex
- }
- func (cf *cacheFilter) handler(
- request []byte,
- context rpc.Context,
- next rpc.NextFilterHandler) (response []byte, err error) {
- if context.GetBool("cache") {
- var ok bool
- cf.RLock()
- if response, ok = cf.Cache[string(request)]; ok {
- cf.RUnlock()
- return response, nil
- }
- cf.RUnlock()
- response, err = next(request, context)
- if err != nil {
- return
- }
- cf.Lock()
- cf.Cache[string(request)] = response
- cf.Unlock()
- return response, nil
- }
- return next(request, context)
- }
- type sizeFilter struct {
- Message string
- }
- func (sf sizeFilter) handler(
- request []byte,
- context rpc.Context,
- next rpc.NextFilterHandler) (response []byte, err error) {
- fmt.Printf("%v request size is %d\r\n", sf.Message, len(request))
- response, err = next(request, context)
- fmt.Printf("%v response size is %d\r\n", sf.Message, len(response))
- return
- }
- type statFilter struct {
- Message string
- }
- func (sf statFilter) handler(
- request []byte,
- context rpc.Context,
- next rpc.NextFilterHandler) (response []byte, err error) {
- start := time.Now()
- response, err = next(request, context)
- end := time.Now()
- fmt.Printf("%v takes %d ms.\r\n", sf.Message, end.Sub(start)/time.Millisecond)
- return
- }
- // TestService is ...
- type TestService struct {
- Test func([]int) ([]int, error) `userdata:"{\"cache\":true}"`
- }
- func main() {
- server := rpc.NewTCPServer("")
- server.AddFunction("test", func(data []int) []int {
- return data
- }).
- AddBeforeFilterHandler(
- statFilter{"Server: BeforeFilter"}.handler,
- sizeFilter{"Server: Compressed"}.handler,
- ).
- AddFilter(CompressFilter{}).
- AddAfterFilterHandler(
- statFilter{"Server: AfterFilter"}.handler,
- sizeFilter{"Server: Non Compressed"}.handler,
- )
- server.Handle()
- client := rpc.NewClient(server.URI())
- client.AddFilter(CompressFilter{}).
- AddBeforeFilterHandler(
- (&cacheFilter{Cache: make(map[string][]byte)}).handler,
- statFilter{"Client: BeforeFilter"}.handler,
- sizeFilter{"Client: Compressed"}.handler,
- ).
- AddAfterFilterHandler(
- statFilter{"Client: AfterFilter"}.handler,
- sizeFilter{"Client: Non Compressed"}.handler,
- )
- var testService *TestService
- client.UseService(&testService)
- args := make([]int, 100000)
- for i := range args {
- args[i] = i
- }
- result, err := testService.Test(args)
- fmt.Println(len(result), err)
- result, err = testService.Test(args)
- fmt.Println(len(result), err)
- client.Close()
- server.Close()
- }
该程序运行结果为:
- Client: Compressed request size is 688893
- Client: Non Compressed request size is 213244
- Server: Compressed request size is 213244
- Server: Non Compressed request size is 688893
- Server: Non Compressed response size is 688881
- Server: AfterFilter takes 5 ms.
- Server: Compressed response size is 213223
- Server: BeforeFilter takes 38 ms.
- Client: Non Compressed response size is 213223
- Client: AfterFilter takes 38 ms.
- Client: Compressed response size is 688881
- Client: BeforeFilter takes 69 ms.
- 100000 <nil>
- 100000 <nil>
我们可以看到两次的执行结果都出来了,但是中间件的输出内容只有一次。原因就是第二次执行时,缓存中间件将缓存的结果直接返回了。因此后面所有的步骤就都略过了。
通过这个例子,我们可以看出,将 Hprose 中间件和 Hprose 过滤器结合,可以实现非常强大的扩展功能。如果你有什么特殊的需求,直接使用 Hprose 无法实现的话,就考虑一下是否可以添加几个 Hprose 中间件和 Hprose 过滤器吧。