通过 HTTP 请求调用 Go Micro 提供的微服务接口
上篇分享我们简单介绍了基于 Go Micro 框架构建第一个微服务接口,并且编写了简单的客户端测试代码,但是这个客户端代码也是集成在 Go Micro 项目中的,需要调用相应的 Go Micro SDK 才能向服务端接口发起请求,如果我们的服务消费者不是基于 Go 语言,而是基于其它语言,如 PHP,这个时候,要怎样从 PHP 项目中调用 Go Micro 提供的微服务接口呢?
我们可以基于 Go Micro 自带的 API 网关功能来实现通过 HTTP 请求从其他语言编写的系统中调用 Go Micro 提供的微服务接口,该 API 网关底层会通过服务发现、负载均衡、RPC 通信来实现对 HTTP 请求和路由的处理。下面我们来简单演示一下其实现流程。
0、安装 Micro
首先我们需要安装微服务开发运行时依赖 Micro,以便可以通过它来启动微服务 API 网关:
go get github.com/micro/micro
安装成功后,可以在项目根目下的 bin
目录中看到 micro
可执行文件:
1、编写 API 接口代码
接下来,我们来编写 API 网关接口代码,开始之前,我们打开之前编写的服务端文件 ~/go/hello/src/hello/main.go
,将底层服务名称调整为 go.micro.srv.greeter
以便于和 API 服务接口名做区分:
func main() {
service := micro.NewService(
micro.Name("go.micro.srv.greeter"),
)
...
}
然后在 ~/go/hello/src/hello
目录下创建一个子目录 api
,用于存放 API 接口相关代码,我们先创建一个 api.go
文件来存放此次服务接口的处理代码:
package main
import (
"context"
"encoding/json"
"github.com/micro/go-micro"
api "github.com/micro/go-micro/api/proto"
"github.com/micro/go-micro/errors"
hello "hello/proto"
"log"
"strings"
)
type Say struct {
Client hello.GreeterService
}
func (s *Say) Hello(ctx context.Context, req *api.Request, rsp *api.Response) error {
log.Print("收到 Say.Hello API 请求")
// 从请求参数中获取 name 值
name, ok := req.Get["name"]
if !ok || len(name.Values) == 0 {
return errors.BadRequest("go.micro.api.greeter", "名字不能为空")
}
// 将参数交由底层服务处理
response, err := s.Client.Hello(ctx, &hello.HelloRequest{
Name: strings.Join(name.Values, " "),
})
if err != nil {
return err
}
// 处理成功,则返回处理结果
rsp.StatusCode = 200
b, _ := json.Marshal(map[string]string{
"message": response.Greeting,
})
rsp.Body = string(b)
return nil
}
func main() {
// 创建一个新的服务
service := micro.NewService(
micro.Name("go.micro.api.greeter"),
)
// 解析命令行参数
service.Init()
// 将请求转发给底层 go.micro.srv.greeter 服务处理
service.Server().Handle(
service.Server().NewHandler(
&Say{Client: hello.NewGreeterService("go.micro.srv.greeter", service.Client())},
),
)
// 运行服务
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
2、启动 API 网关
编写好 API 接口代码后,依次启动 main.go
和 api.go
,最后通过 micro api
启动 API 网关等待客户端请求:
cd ~/go/hello/src/hello
go run main.go
go run api/api.go // API 依赖底层 go.micro.srv.greeter 服务
micro api --handler=api // 启动 API 网关处理 HTTP 请求,--handle 参数不能为空,否则可能报错
micro api
启动过程中,可以看到注册了 RPC 处理器和 API 请求处理器,HTTP 请求监听端口默认是 8080
:
以上代码执行完毕,所有服务启动就绪后,可以在 Consul Web 页面中看到注册的服务信息如下:
3、调用微服务接口
接下来,我们就可以从客户端调用注册到 Consul 的服务,具体有两种方式,一种是通过 API 接口,另一种是绕过 API 接口直接调用底层的 RPC 服务:
API 接口
我们可以通过 http://localhost:8080/greeter/say/hello
对 API 接口进行请求,该 URL 会被路由到 go.micro.api.greeter
服务的 Say.Hello
方法进行处理,如果不传递 name
参数,会报错:
如果按照服务接口约定传递参数,则返回问候信息,该问候信息最终是通过 go.micro.srv.greeter
服务的 Greeter.Hello
方法生成并返回,再由 go.micro.api.greeter
服务的 Say.Hello
方法包装后返回给客户端:
你可以在 PHP 中通过 curl 扩展或者 Guzzle 包对上述 API 接口请求进行封装,从而实现在 PHP 中请求 Go Micro 微服务接口。
RPC 接口
此外,我们还可以通过下面这种调用方式绕开 API 接口,直接调用 go.micro.srv.greeter
提供的 RPC 服务接口,此时需要通过 POST 方式对 http://localhost:8080/rpc
发起请求,并在请求实体中带上服务名、方法以及请求参数信息:
curl -H 'Content-Type: application/json' \
-d '{"service": "go.micro.srv.greeter", "method": "Greeter.Hello", "request": {"name": " 学院君"}}' \
http://localhost:8080/rpc
如果是在 Postman 中,则演示结果界面如下:
好了,以上就是从其他语言实现的服务消费端调用 Go Micro 微服务接口的简单示例,现在,我们已经简单串起了客户端、API 网关和微服务接口调用这条完整链路,后续我们将就其中的底层实现细节以及实际生产环境中更复杂场景的优化进行介绍,此外,我们还将就服务治理、监控以及故障定位在 Go Micro 中的落地进行介绍。
31 Comments
micro --registry=consul api --handler=api 因为默认的consul被移除了,所以总是不成功 发现issue中有解决方法 需要github.com/micro/micro下新建一个plugins.go
go build -o micro main.go plugins.go
重新生成micro文件 即可指定 --registry=consul
是的 改由 micro plugins 提供了
解决办法: 如是gopath的可以按照一楼的办法 如是go mod的可以找到
$gopath/pkg/mod/github.com/micro/micro@v1.18.0
下新建一个plugins.go然后再该目录下执行
go build -o micro main.go plugins.go
重新生成micro可执行文件,然后复制到$gopath/bin
下替换原来的micro可执行文件 再执行micro api --handler=api
即可访问的时候提示: { "id": "go.micro.client", "code": 500, "detail": "Bad Request: HTTP status code 400; transport: received the unexpected content-type "text/plain; charset=utf-8"", "status": "Internal Server Error" } 学院君有遇到吗?
按一楼操作之后,执行命令
{ "id": "go.micro.client.transport", "code": 500, "detail": "malformed HTTP response "\x00\x00\x06\x04\x00\x00\x00\x00\x00\x00\x05\x00\x00@\x00"", "status": "Internal Server Error" }
这种错误有没有谁遇到过
有,我也是
我换成了第二个rpc调用试了一下
应该是没注册上的问题,我用的etcd注册的,没有报错,但是etcd里面没有显示注册信息 server:
api:
etcd:
micro api
我现在是还卡在这里
可以启动下 Micro Web 看看是否真的注册成功:https://xueyuanjun.com/post/21189
我也是报同样的错,卡在这个地方继续不下去了,micro web下显示服务也注册成功,用micro web客户端调用也是 { "id": "go.micro.client.transport", "code": 500, "detail": "malformed HTTP response "\x00\x00\x06\x04\x00\x00\x00\x00\x00\x00\x05\x00\x00@\x00"", "status": "Internal Server Error" },急死人