调用中间件

调用中间件的形式为:

  1. func(
  2. name string,
  3. args []reflect.Value,
  4. context Context,
  5. next NextInvokeHandler) (results []reflect.Value, err error) {
  6. ...
  7. results, err = next(name, args, context)
  8. ...
  9. return results, err
  10. }

name 是调用的远程函数/方法名。

args 是调用参数,引用传递的数组。

context 是调用上下文对象。

next 表示下一个中间件。通过调用 next 将各个中间件串联起来。

在调用 next 之前的操作在调用发生前执行,在调用 next 之后的操作在调用发生后执行,如果你不想修改返回结果,你应该将 next 的返回值作为该中间件的返回值返回。

如果在调用 next 之前的操作中发生 panic,则 next 和后面的代码都不会被执行而是直接返回上一层,panic 信息作为 error 结果返回给上一层中间件。

调用中间件可以是普通函数/方法,也可以是匿名函数。

跟踪调试

我们来看一个例子:

  1. package main
  2.  
  3. import (
  4. "fmt"
  5. "reflect"
  6.  
  7. "github.com/hprose/hprose-golang/rpc"
  8. )
  9.  
  10. func logInvokeHandler(
  11. name string,
  12. args []reflect.Value,
  13. context rpc.Context,
  14. next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
  15. fmt.Printf("%s(%v) = ", name, args)
  16. results, err = next(name, args, context)
  17. fmt.Printf("%v %v\r\n", results, err)
  18. return
  19. }
  20.  
  21. func hello(name string) string {
  22. return "Hello " + name + "!"
  23. }
  24.  
  25. type HelloService struct {
  26. Hello func(string) (string, error)
  27. Hi func(string) error
  28. }
  29.  
  30. func main() {
  31. server := rpc.NewTCPServer("")
  32. server.AddInvokeHandler(logInvokeHandler)
  33. server.AddFunction("hello", hello)
  34. server.Handle()
  35. client := rpc.NewClient(server.URI())
  36. var helloService *HelloService
  37. client.UseService(&helloService)
  38. helloService.Hello("World")
  39. helloService.Hi("World")
  40. client.Close()
  41. server.Close()
  42. }

运行该程序,我们会看到如下结果:


  1. Hello([World]) = [Hello World!] <nil>
  2. Hi([<interface {} Value>]) = [] Can't find this method Hi

如果把:

  1. server.AddInvokeHandler(logInvokeHandler)

去掉,在创建客户端之后,加上下面这句:

  1. client.AddInvokeHandler(logInvokeHandler)

再运行该程序,我们会看到如下输出:


  1. Hello([World]) = [Hello World!] <nil>
  2. Hi([World]) = [] Can't find this method Hi

我们会发现,关于 Hello 方法调用的输出是一样的,关于 Hi 方法的调用,参数上不太一样。原因是客户端的参数总是跟调用时带入的参数值类型一致的,而在服务器端的参数类型是跟服务器端服务函数/方法的参数定义类型一致,而 Hi 方法在服务器并没有定义,因此,在反序列化时,是按照 interface{} 类型反序列化的,所以在服务器端看到的是一个 interface{} 类型的值。