• 调用中间件
    • 跟踪调试

    调用中间件

    调用中间件的形式为:

    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{} 类型的值。