1

go-micro api version

 2 years ago
source link: https://ioridy.github.io/2020/07/27/go-micro-api-version/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

go-micro api version

2020-07-27

go-micro的api版本机制看example的时候感觉很简单,但是实际要是用的时候,还是有好几个点费了不少时间,最终通过扒code弄的差不多了,这里记录下。

go-micro可以提供同时提供http和grpc的访问,如果不是用自定义的EndPoint时,这两种的api版本控制没有区别,下面分别说下这几种情况下的版本控制机制。

grpc的访问主要是通过protobuf文件生成的对应语言的文件来访问,所以版本控制是通过protobuf中的package定义来控制的,只需要在package的定义中加入版本信息即可,比如:

//v1
package go.micro.api.v1.test;

//v2
package go.micro.api.v2.test;

这里我理解只要package定义不一样,可以区别出具体的服务即可,v1和v2主要是语义上好理解

版本号建议加载api之后,这样可以保持和http访问时的一致(go-micro api gateway可自动转换grpc到http,下边会详细说)

go-micro的http访问主要是通过micro的api网关实现的,目前有两种形式:

/[service]/[method]

http的url按照上面的规则解析,动态转化为rpc的访问,以上面的package定义为例

//v1
package go.micro.api.v1.test;
//url v1/test/hello

//v2
package go.micro.api.v2.test;
//url v2/test/hello


// hello func defined

下面还有几个url解析的官方example更明了一点

Path Service Method /foo/bar go.micro.api.foo Foo.Bar /foo/bar/baz go.micro.api.foo Bar.Baz /foo/bar/baz/cat go.micro.api.foo.bar Baz.Cat

Versioned API URLs can easily be mapped to service names:

Path Service Method /foo/bar go.micro.api.foo Foo.Bar /v1/foo/bar go.micro.api.v1.foo Foo.Bar /v1/foo/bar/baz go.micro.api.v1.foo Bar.Baz /v2/foo/bar go.micro.api.v2.foo Foo.Bar /v2/foo/bar/baz go.micro.api.v2.foo Bar.Baz

code中的实现逻辑是:

  1. 分割url为数组
  2. 根据数组的长度来构建service和method

    • 少于等于2,第一个作为service,整体作为method

         // If we've got two or less parts
      // Use first part as service
      // Use all parts as method
      if len(parts) <= 2 {
      name := parts[0]
      return name, methodName(parts)
      }
    • 等于3,前面2个作为service,后边2个为method

             // Treat /v[0-9]+ as versioning where we have 3 parts
      // /v1/foo/bar => service: v1.foo method: Foo.bar
      if len(parts) == 3 && versionRe.Match([]byte(parts[0])) {
      name := strings.Join(parts[:len(parts)-1], ".")
      r
    • 大于3,最后两个作为method,其余所有作为service

         // Service is everything minus last two parts
      // Method is the last two parts
      name := strings.Join(parts[:len(parts)-2], ".")
      return name, methodName(parts[len(parts)-2:])

      EndPoint

endpoint是上面不同的是,因为url是自己定义的,所以上面的方式解析出来的结果是错误的,所以必须在用url比对路由的地址的时候,就成功,否则就会报错

我这边想到的版本就是在设置EndPoint的时候加入版本号(客户端请求会带版本后,为了在比对的时候保持一致来保证成功找到注册的EndPoint),找到endpoint之后的流程就相同了,这里不过多描述。

之后我会在专门写一篇文章,从code追踪下整个url的解析过程,就会清楚为什么需要保证url一致,比对成功

func registerUser(server server.Server) error {
return pb.RegisterUserHandler(server, new(Handler),
mApi.WithEndpoint(&mApi.Endpoint{
// The RPC method
Name: "User.Register",
// The HTTP paths. This can be a POSIX regex
Path: []string{"^v1/user/register$"},
// The HTTP Methods for this endpoint
Method: []string{"POST"},
// The API handler to use
Handler: rpc.Handler,
}),
)
}

这里的版本号需要和**protobuf文件中的package定义的一致,否则还是服务找到对应的服务(上边提到了version添加的位置),因为最终还是需要通过rpc来访问具体的服务的。

这里还有个问题,就是在main中,初始化micro服务的时候,设置的version到目前为止都没有用到,我好奇搜索了下version关键字,有发现client/selector/filter.go中有对应version的使用,看位置应该是client用来过滤服务的,不过没细看,留个坑,之后来填。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK