kratos api定义http grpc双协议 4 months ago
博客大纲
根据 Kratos 文档的说明,通过 Protobuf IDL(Interface Definition Language)可以同时定义 REST API 和 gRPC API。以下是一个全面的例子,展示如何使用 Protobuf 定义一个服务,包括 gRPC 方法和对应的 REST API 映射,并提供生成代码的步骤。这个例子基于一个简单的“用户管理”服务。
1. Protobuf 文件定义
我们将创建一个 user.proto
文件,定义一个用户管理服务,支持获取用户信息和创建用户。文件内容如下:
syntax = "proto3";
package user.v1;
import "google/api/annotations.proto";
// 指定 Go 包路径
option go_package = "github.com/example/user-service/api/user/v1;v1";
// Java 相关选项(可选)
option java_multiple_files = true;
option java_package = "com.example.user.v1";
option java_outer_classname = "UserProtoV1";
// 定义 UserService 服务
service UserService {
// 获取用户信息 (GetUser)
rpc GetUser (GetUserRequest) returns (GetUserResponse) {
option (google.api.http) = {
get: "/v1/users/{id}" // REST API 的 GET 方法
};
}
// 创建用户 (CreateUser)
rpc CreateUser (CreateUserRequest) returns (CreateUserResponse) {
option (google.api.http) = {
post: "/v1/users" // REST API 的 POST 方法
body: "*" // 请求体映射到整个 CreateUserRequest
};
}
}
// 获取用户请求消息
message GetUserRequest {
string id = 1; // 用户 ID
}
// 获取用户响应消息
message GetUserResponse {
string id = 1;
string name = 2;
string email = 3;
}
// 创建用户请求消息
message CreateUserRequest {
string name = 1;
string email = 2;
}
// 创建用户响应消息
message CreateUserResponse {
string id = 1;
string name = 2;
string email = 3;
}
说明:
syntax = "proto3"
: 使用 Protocol Buffers 的第 3 版语法。package user.v1
: 定义命名空间,避免冲突,通常包含服务名和版本。import "google/api/annotations.proto"
: 引入 Google 的 HTTP 注解,用于映射 REST API。option go_package
: 指定生成的 Go 代码的包路径。service UserService
: 定义服务,包含两个方法:GetUser
: 获取用户信息,支持 gRPC 和 REST(GET 方法)。CreateUser
: 创建用户,支持 gRPC 和 REST(POST 方法)。
google.api.http
: 为每个方法指定 REST API 的 HTTP 方法和路径。get: "/v1/users/{id}"
: 将GetUser
映射为 HTTP GET 请求,id
是路径参数。post: "/v1/users"
: 将CreateUser
映射为 HTTP POST 请求,请求体映射到整个CreateUserRequest
。
2. 生成代码
假设上述文件保存为 api/user/v1/user.proto
,我们需要使用 protoc
工具生成 Go 代码。以下是命令:
安装必要的工具
确保已安装以下工具:
- protoc
: Protocol Buffers 编译器。
- protoc-gen-go
: Go 语言插件。
- protoc-gen-go-http
: Kratos 的 HTTP 插件,用于生成 REST API 代码。
- protoc-gen-go-grpc
: gRPC 插件。
安装命令(以 Go 为例):
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
生成代码
运行以下命令生成代码:
protoc --proto_path=. \
--go_out=. \
--go-grpc_out=. \
--go-http_out=. \
api/user/v1/user.proto
生成的文件
执行后,会在 api/user/v1/
目录下生成以下文件:
- user.pb.go
: 包含消息的结构体定义和序列化代码。
- user_grpc.pb.go
: 包含 gRPC 的服务接口和客户端存根。
- user_http.pb.go
: 包含 REST API 的 HTTP 处理函数。
3. 服务端实现
以下是一个简单的服务端实现,使用 Go 和 Kratos 框架。
项目结构
user-service/
├── api/
│ └── user/
│ └── v1/
│ ├── user.proto
│ ├── user.pb.go
│ ├── user_grpc.pb.go
│ └── user_http.pb.go
├── internal/
│ └── service/
│ └── user.go
├── cmd/
│ └── main.go
└── go.mod
服务实现 (internal/service/user.go
)
package service
import (
pb "github.com/example/user-service/api/user/v1"
"context"
)
type UserService struct {
pb.UnimplementedUserServiceServer
}
func NewUserService() *UserService {
return &UserService{}
}
func (s *UserService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
// 模拟获取用户信息
return &pb.GetUserResponse{
Id: req.Id,
Name: "John Doe",
Email: "john@example.com",
}, nil
}
func (s *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
// 模拟创建用户
return &pb.CreateUserResponse{
Id: "123",
Name: req.Name,
Email: req.Email,
}, nil
}
主程序 (cmd/main.go
)
package main
import (
"flag"
"log"
"github.com/go-kratos/kratos/v2"
"github.com/go-kratos/kratos/v2/transport/grpc"
"github.com/go-kratos/kratos/v2/transport/http"
pb "github.com/example/user-service/api/user/v1"
"github.com/example/user-service/internal/service"
)
func main() {
flag.Parse()
// 创建 HTTP 服务
httpSrv := http.NewServer(http.Address(":8000"))
// 创建 gRPC 服务
grpcSrv := grpc.NewServer(grpc.Address(":9000"))
// 初始化服务
userService := service.NewUserService()
// 注册 HTTP 和 gRPC 服务
pb.RegisterUserServiceHTTPServer(httpSrv, userService)
pb.RegisterUserServiceServer(grpcSrv, userService)
// 创建 Kratos 应用
app := kratos.New(
kratos.Name("user-service"),
kratos.Server(
httpSrv,
grpcSrv,
),
)
// 启动应用
if err := app.Run(); err != nil {
log.Fatal(err)
}
}
4. 测试服务
测试 gRPC
使用 gRPC 客户端(如 grpcurl
)测试:
# 获取用户信息
grpcurl -plaintext -d '{"id": "123"}' localhost:9000 user.v1.UserService/GetUser
# 创建用户
grpcurl -plaintext -d '{"name": "Alice", "email": "alice@example.com"}' localhost:9000 user.v1.UserService/CreateUser
测试 REST API
使用 curl
测试 REST 接口:
# 获取用户信息 (GET)
curl http://localhost:8000/v1/users/123
# 创建用户 (POST)
curl -X POST http://localhost:8000/v1/users -d '{"name": "Alice", "email": "alice@example.com"}'
5. 总结
这个例子展示了如何通过 Protobuf IDL 定义一个同时支持 gRPC 和 REST API 的服务:
- 定义阶段: 在
.proto
文件中定义服务和消息,并使用google.api.http
注解映射 REST 路径。 - 生成阶段: 使用
protoc
生成 Go 代码,包括 gRPC 和 HTTP 的实现。 - 实现阶段: 在 Go 中实现服务逻辑,并使用 Kratos 启动 HTTP 和 gRPC 服务。
- 测试阶段: 使用工具验证 gRPC 和 REST 接口的功能。
这种方式利用了 Protobuf 的强类型和跨语言优势,同时结合 Kratos 框架支持 REST 和 gRPC 的双协议特性,非常适合微服务架构。